package model

import (
	"bufio"
	"config-client-v1/init/global"
	j_log "config-client-v1/init/j-log"
	"config-client-v1/utils/tools"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/olekukonko/tablewriter"
	"io"
	"net"
	"os"
	"runtime/debug"
	"strconv"
	"strings"
	"sync"
	"time"
)

type TCPClient struct {
	RemoteAddr    string              `json:"remote_addr"`
	Connection    net.Conn            `json:"-"`
	Reader        *bufio.Reader       `json:"-"`
	CreateTime    string              `json:"create_time"`
	LastDataTime  string              `json:"last_data_time"`
	Requests      *FSTCPRequestMapStu `json:"-"` // 当前client的所有请求, 时间戳为key
	FrameCacheMap *FrameCacheMapStu   `json:"-"` // 帧缓存(分帧用)
}

// RunSync 运行阶段发送运行同步
func (fse *FSEquip) RunSync(ctx context.Context) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"RunSync panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("fs_id=%d, 协程已停止, RunSync 协程已关闭", fse.ID)})
	}()
	for {
		select {
		case <-ctx.Done():
			return
		default:
			if fse.Stage == 1 && fse.DSMatched == 1 { // FS处于运行状态且数据规模一致才可以运行同步
				//j_log.LogInfo([]interface{}{fmt.Sprintf("fs_id=%d RunSync stage=%d, matched=%d...", fse.ID, fse.Stage, fse.DSMatched)})
				data := GenFSFrameData0603(fse)
				_, err := fse.Write(data)
				if err != nil {
					j_log.LogError([]interface{}{"自动运行同步写入tcp失败", err.Error()})
				}
			}
			time.Sleep(time.Duration(fse.SyncRate) * time.Millisecond)
		}
	}
}

// ReadIP 组态阶段发送读取IP指令, 当心跳包使用
func (fse *FSEquip) ReadIP(ctx context.Context) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"ReadIP panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("fs_id=%d, 协程已停止, ReadIP 协程已关闭", fse.ID)})
	}()
	for {
		select {
		case <-ctx.Done():
			return
		default:
			if fse.Stage == 0 {
				//j_log.LogInfo([]interface{}{fmt.Sprintf("fs_id=%d ReadIP stage=%d, matched=%d...", fse.ID, fse.Stage, fse.DSMatched)})
				data := GenFSFrameData0101()
				_, err := fse.Write(data)
				if err != nil {
					j_log.LogError([]interface{}{"读取IP失败", err.Error()})
				}
			}
			time.Sleep(time.Duration(fse.SyncRate) * time.Millisecond)
		}
	}
}

func (fse *FSEquip) DataScaleGet() {
	if fse.Stage == 1 {
		return
	}
	time.Sleep(1 * time.Second)
	data := GenFSFrameData0401()
	_, err := fse.Write(data)
	if err != nil {
		j_log.LogError([]interface{}{"GenFSFrameData0401 fse.Write error", err.Error()})
		return
	}
	//j_log.LogInfo([]interface{}{"组态阶段自动获取FS规模"})
	time.Sleep(1 * time.Second)
	data = GenFSFrameData0501()
	_, err = fse.Write(data)
	if err != nil {
		j_log.LogError([]interface{}{"GenFSFrameData0501 fse.Write error", err.Error()})
		return
	}
	//j_log.LogInfo([]interface{}{"组态阶段自动获取模型规模"})

}

func (fse *FSEquip) RunFSTcpClient() {
	defer func() {
		if err2 := recover(); err2 != nil {
			j_log.LogError([]interface{}{"RunFSTcpClient panic", err2})
			fmt.Println(string(debug.Stack()))
		}
		if fse.RunningState == 3 {
			j_log.LogInfo([]interface{}{"FS设备已停止", fse.Name, fse.IP, fse.Port})
			fse.RunningState = 4
			RunningFSMap.Delete(fse.ID)
			_ = fse.UpdateRunningState(4, "FS设备TCP已断开")
			ResetRunningProject()
			return
		}
		fse.RunningState = 5
		j_log.LogInfo([]interface{}{"3秒后重连...", fse.Name})
		_ = fse.UpdateRunningState(5, "FS设备TCP正在尝试重连")
		time.Sleep(2 * time.Second)

		if fse.RunningState == 3 {
			j_log.LogInfo([]interface{}{"FS设备TCP已断开", fse.Name, fse.IP, fse.Port})
			fse.RunningState = 4
			RunningFSMap.Delete(fse.ID)
			_ = fse.UpdateRunningState(4, "FS设备TCP已断开")
			ResetRunningProject()
			return
		}
		fse.ReconnectTimes++
		fse.RunFSTcpClient()
	}()
	if fse.TcpClient == nil {
		fse.TcpClient = &TCPClient{
			Requests:      NewFSTCPRequestMap(),
			FrameCacheMap: NewFrameCacheMap(),
		}
	}
	addr := ""
	if fse.ReconnectTimes%6 <= 2 { // 余数 [0,1,2] 连主服务器, [3,4,5] 连冗余服务器
		addr = fmt.Sprintf("%s:%d", fse.IP, fse.Port)
		j_log.LogInfo([]interface{}{"正在连接主server", fse.Name, addr})
	} else {
		if fse.RedundantEnable == 0 {
			addr = fmt.Sprintf("%s:%d", fse.IP, fse.Port)
			j_log.LogInfo([]interface{}{"正在连接主server", fse.Name, addr})
		} else {
			addr = fmt.Sprintf("%s:%d", fse.RedundantIP, fse.RedundantPort)
			j_log.LogInfo([]interface{}{"正在连接冗余server", fse.Name, addr})
		}
	}
	conn, err0 := net.Dial("tcp", addr)
	if err0 != nil {
		fse.tcpErrorHandle(err0)
		return
	}
	defer conn.Close()

	j_log.LogInfo([]interface{}{"TCP连接成功", fse.Name, addr})
	fse.TcpClient.Connection = conn
	fse.TcpClient.RemoteAddr = conn.RemoteAddr().String()
	fse.TcpClient.Reader = bufio.NewReader(fse.TcpClient.Connection) // 创建一个tcp返回 reader

	fse.RunningState = 2
	fse.Detail = "TCP连接成功"
	_ = fse.UpdateRunningState(2, "TCP连接成功")
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go fse.RunSync(ctx)
	go fse.DataScaleGet()
	//go fse.ReadIP(ctx)
	var cacheBuffer [ByteLENGTH]byte
loop0:
	for {
		n0, err := fse.TcpClient.Reader.Read(cacheBuffer[0:])
		if err != nil {
			if err == io.EOF {
				fse.Detail = "read error io.EOF." + err.Error()
				j_log.LogError([]interface{}{"read error io.EOF.", fse.Name, addr})
			} else if err == net.ErrClosed || strings.Contains(err.Error(), "use of closed network connection") || strings.Contains(err.Error(), "read: connection reset by peer") || strings.Contains(err.Error(), "closed by the remote host") {
				fse.Detail = "read error PING." + err.Error()
				j_log.LogError([]interface{}{"read error PING.", fse.Name, addr})
			} else {
				fse.Detail = "read error unknown." + err.Error()
				j_log.LogError([]interface{}{"read error unknown.", fse.Name, addr, err.Error()})
			}
			return
		}
		buffer := cacheBuffer[0:n0]
		//fmt.Println(buffer[0:n])
		str0 := tools.ByteArrayToHexStr(buffer[0:n0])
		_ = tools.WriteStringToLog(fmt.Sprintf("[%s~%s]【recv】len=%d#%s", tools.GetNow(), fse.TcpClient.RemoteAddr, n0, str0), "fs_data_all.log", "a") // 可能是粘包异常
		//j_log.LogInfo([]interface{}{"【recv】", fse.TcpClient.RemoteAddr, fmt.Sprintf("len=%d", n0)})
		if n0 < 6 {
			j_log.LogError([]interface{}{"数据帧长度n0小于6", fse.Name, addr})
			continue
		}
		if buffer[0] != 0x5a || buffer[n0-1] != 0xa5 {
			j_log.LogError([]interface{}{"无效的帧头帧尾", fse.Name, addr})
			continue
		}
		length := tools.BytesToUint16(buffer[3:5], fse.IntEndian)
		if int(length) > n0 { // length 为第一帧长度, n0为本次数据包长度, 一个数据包可能包含多个帧(粘包情况)
			j_log.LogError([]interface{}{"数据帧长度length与实际n0不匹配", fmt.Sprintf("length=%d, n0=%d\n", length, n0)})
			continue
		} else {
			if n0 > int(length) {
				_ = tools.WriteStringToLog(str0, "tcp_segment_coalescence.txt", "") // 可能是粘包异常
			}
			for {
				currentFrameLength := int(tools.BytesToUint16(buffer[3:5], fse.IntEndian)) // 当前帧数据长度
				if buffer[0] != 0x5a || buffer[currentFrameLength-1] != 0xa5 {
					j_log.LogError([]interface{}{"无效的帧头帧尾~", fse.Name, addr})
					continue loop0
				}
				str := tools.ByteArrayToHexStr(buffer[0:currentFrameLength])
				funcCode := buffer[1]
				cmdCode := buffer[2]
				switch funcCode {
				case 0x01:
					switch cmdCode {
					case 0x01:
						i := 7
						redundantEnable := FSBoolToNormalBool(buffer[i])
						i++
						ip1Part1 := buffer[i]
						i++
						ip1Part2 := buffer[i]
						i++
						ip1Part3 := buffer[i]
						i++
						ip1Part4 := buffer[i]
						i++
						ip1Port := tools.BytesToUint16(buffer[i:i+2], fse.IntEndian)
						i += 2
						ip2Part1 := buffer[i]
						i++
						ip2Part2 := buffer[i]
						i++
						ip2Part3 := buffer[i]
						i++
						ip2Part4 := buffer[i]
						i++
						ip2Port := tools.BytesToUint16(buffer[i:i+2], fse.IntEndian)
						i += 2
						param1 := tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian)
						i += 4
						param2 := tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian)
						i += 4
						param3 := tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian)
						i += 4
						j_log.LogInfo([]interface{}{fmt.Sprintf("读取到IP: 冗余开闭=%d,IP1=%d.%d.%d.%d:%d,IP2=%d.%d.%d.%d:%d,参数1=%.2f,参数2=%.2f,参数3=%.2f", redundantEnable, ip1Part1, ip1Part2, ip1Part3, ip1Part4, ip1Port, ip2Part1, ip2Part2, ip2Part3, ip2Part4, ip2Port, param1, param2, param3)})
						data := &FSEquip{
							IP:              fmt.Sprintf("%d.%d.%d.%d", ip1Part1, ip1Part2, ip1Part3, ip1Part4),
							Port:            int(ip1Port),
							RedundantEnable: redundantEnable,
							RedundantIP:     fmt.Sprintf("%d.%d.%d.%d", ip2Part1, ip2Part2, ip2Part3, ip2Part4),
							RedundantPort:   int(ip2Port),
							RedundantParam1: float64(param1),
							RedundantParam2: float64(param2),
							RedundantParam3: float64(param3),
						}
						IPReadHandle(fse, data)
						ResponseDo(fse, "0101", str)
					case 0x81:
						ResponseDo(fse, "0181", str)
					case 0x02:
						ResponseDo(fse, "0102", str)
					case 0x82:
						ResponseDo(fse, "0182", str)
					default:
						j_log.LogError([]interface{}{"暂不支持的指令码", funcCode, cmdCode})
					}
				case 0x02:
					switch cmdCode {
					case 0x02:
						ResponseDo(fse, "0202", str)
					case 0x82:
						ResponseDo(fse, "0282", str)
					case 0x03:
						ResponseDo(fse, "0203", str)
					case 0x83:
						ResponseDo(fse, "0283", str)
					case 0x04:
						ResponseDo(fse, "0204", str)
					case 0x84:
						ResponseDo(fse, "0284", str)
					case 0x05:
						ResponseDo(fse, "0205", str)
					case 0x85:
						ResponseDo(fse, "0285", str)
					case 0x06:
						ResponseDo(fse, "0206", str)
					case 0x86:
						ResponseDo(fse, "0286", str)
					}
				case 0x03:
					switch cmdCode {
					case 0x01:
						ResponseDo(fse, "0301", str)
					case 0x81:
						ResponseDo(fse, "0381", str)
					case 0x02:
						ResponseDo(fse, "0302", str)
					case 0x82:
						ResponseDo(fse, "0382", str)
					case 0x03:
						ResponseDo(fse, "0303", str)
					case 0x83:
						ResponseDo(fse, "0383", str)
					case 0x04:
						ResponseDo(fse, "0304", str)
					case 0x84:
						ResponseDo(fse, "0384", str)
					case 0x05:
						ResponseDo(fse, "0305", str)
					case 0x85:
						ResponseDo(fse, "0385", str)
					case 0x06:
						ResponseDo(fse, "0306", str)
					case 0x86:
						ResponseDo(fse, "0386", str)
					case 0x07:
						ResponseDo(fse, "0307", str)
					case 0x87:
						ResponseDo(fse, "0387", str)
					case 0x08:
						ResponseDo(fse, "0308", str)
					case 0x88:
						ResponseDo(fse, "0388", str)
					}
				case 0x04:
					switch cmdCode {
					case 0x01:
						ds := &DataScale{}
						i := 7
						ds.AI = buffer[i]
						i++
						ds.DI = buffer[i]
						i++
						ds.AQ = buffer[i]
						i++
						ds.DQ = buffer[i]
						i++
						ds.Other = buffer[i]
						i++
						ds.EData = tools.BytesToUint16(buffer[i:i+2], fse.IntEndian)
						fmt.Printf("数据规模: AI=%d, DI=%d, AQ=%d, DQ=%d, Other=%d, EData=%d\n",
							ds.AI, ds.DI, ds.AQ, ds.DQ, ds.Other, ds.EData)
						TempFSMap.UpdateDS(fse.ID, ds, "module")
						ResponseDo(fse, "0401", str)
						fse.DSModuleRead = time.Now().Unix()
					case 0x81:
						ResponseDo(fse, "0481", str)
					case 0x02:
						moduleType := "AI"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0402】 %s模块上载 %s", moduleType, addr)})
						if currentFrameLength < 15 {
							j_log.LogWarning([]interface{}{"0402 数据帧长度小于15,数据帧无效", currentFrameLength})
							continue loop0
						}
						dataPart := make([]*FrameItem, 0)
						moduleNumber := buffer[8]
						channelQuantity := buffer[9]
						contentBytes := buffer[10 : currentFrameLength-5]
						code1 := fse.Code1
						code2 := AllowModuleCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)

						blockLength := 28
						if len(contentBytes) != int(channelQuantity)*blockLength {
							fmt.Printf("[%s ~ %02d%02d]# %s 通道数与实际不匹配\n", tools.GetNow(), funcCode, cmdCode, moduleType)
							continue loop0
						}
						tableData := make([][]string, 0)
						for i := 0; i < int(channelQuantity); i++ {
							upperLimitValue := tools.BytesToFloat32(contentBytes[i*blockLength:i*blockLength+4], fse.FloatEndian)
							lowerLimitValue := tools.BytesToFloat32(contentBytes[i*blockLength+4:i*blockLength+8], fse.FloatEndian)
							upper2LimitValue := tools.BytesToFloat32(contentBytes[i*blockLength+8:i*blockLength+12], fse.FloatEndian)
							lower2LimitValue := tools.BytesToFloat32(contentBytes[i*blockLength+12:i*blockLength+16], fse.FloatEndian)
							rangeUpperValue := tools.BytesToFloat32(contentBytes[i*blockLength+16:i*blockLength+20], fse.FloatEndian)
							rangeLowerValue := tools.BytesToFloat32(contentBytes[i*blockLength+20:i*blockLength+24], fse.FloatEndian)
							shield := contentBytes[i*blockLength+24]
							alertBit := contentBytes[i*blockLength+25]
							formula := contentBytes[i*blockLength+26]
							diagMode := contentBytes[i*blockLength+27]
							tableData = append(tableData, []string{
								fmt.Sprintf("%03d", i+1),
								fmt.Sprintf("%.2f", upperLimitValue),
								fmt.Sprintf("%.2f", lowerLimitValue),
								fmt.Sprintf("%.2f", upper2LimitValue),
								fmt.Sprintf("%.2f", lower2LimitValue),
								fmt.Sprintf("%.2f", rangeUpperValue),
								fmt.Sprintf("%.2f", rangeLowerValue),
								fmt.Sprintf("%d", shield),
								fmt.Sprintf("%d", alertBit),
								fmt.Sprintf("%d", formula),
								fmt.Sprintf("%d", diagMode),
							})
							tmp := &FrameItem{
								Code1:            code1,
								Code2:            code2,
								Code3:            code3,
								Code4:            fmt.Sprintf("%03d", i+1),
								ChannelType:      moduleType,
								Addr:             fmt.Sprintf("%s-%s-%s-%s", code1, code2, code3, fmt.Sprintf("%03d", i+1)),
								UpperLimitValue:  float64(upperLimitValue),
								LowerLimitValue:  float64(lowerLimitValue),
								Upper2LimitValue: float64(upper2LimitValue),
								Lower2LimitValue: float64(lower2LimitValue),
								RangeUpperLimit:  float64(rangeUpperValue),
								RangeLowerLimit:  float64(rangeLowerValue),
								Shield:           FSBoolToNormalBool(shield),
								AlertBit:         FSBoolToNormalBool(alertBit),
								Formula:          formula,
								DiagMode:         diagMode,
							}
							dataPart = append(dataPart, tmp)
						}

						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"通道号", "上限", "下限", "上上限", "下下限", "量程上限", "量程下限", "屏蔽", "报警", "计算公式", "诊断模式"})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						ModuleUploadHandle(fse, moduleType, moduleNumber, code2, code3, dataPart)
						ResponseDo(fse, "0402", str)
					case 0x82:
						ResponseDo(fse, "0482", str)
					case 0x03:
						moduleType := "AQ"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0403】 %s模块上载 %s", moduleType, addr)})
						if currentFrameLength < 15 {
							j_log.LogWarning([]interface{}{"0403 数据帧长度小于15,数据帧无效", currentFrameLength})
							continue loop0
						}
						dataPart := make([]*FrameItem, 0)
						moduleNumber := buffer[8]
						channelQuantity := buffer[9]
						contentBytes := buffer[10 : currentFrameLength-5]
						code1 := fse.Code1
						code2 := AllowModuleCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)

						blockLength := 28
						if len(contentBytes) != int(channelQuantity)*blockLength {
							fmt.Printf("[%s ~ %02d%02d]# %s 通道数与实际不匹配\n", tools.GetNow(), funcCode, cmdCode, moduleType)
							continue loop0
						}
						tableData := make([][]string, 0)
						for i := 0; i < int(channelQuantity); i++ {
							upperLimitValue := tools.BytesToFloat32(contentBytes[i*blockLength:i*blockLength+4], fse.FloatEndian)
							lowerLimitValue := tools.BytesToFloat32(contentBytes[i*blockLength+4:i*blockLength+8], fse.FloatEndian)
							upper2LimitValue := tools.BytesToFloat32(contentBytes[i*blockLength+8:i*blockLength+12], fse.FloatEndian)
							lower2LimitValue := tools.BytesToFloat32(contentBytes[i*blockLength+12:i*blockLength+16], fse.FloatEndian)
							rangeUpperValue := tools.BytesToFloat32(contentBytes[i*blockLength+16:i*blockLength+20], fse.FloatEndian)
							rangeLowerValue := tools.BytesToFloat32(contentBytes[i*blockLength+20:i*blockLength+24], fse.FloatEndian)
							shield := contentBytes[i*blockLength+24]
							alertBit := contentBytes[i*blockLength+25]
							formula := contentBytes[i*blockLength+26]
							diagMode := contentBytes[i*blockLength+27]
							tableData = append(tableData, []string{
								fmt.Sprintf("%03d", i+1),
								fmt.Sprintf("%.2f", upperLimitValue),
								fmt.Sprintf("%.2f", lowerLimitValue),
								fmt.Sprintf("%.2f", upper2LimitValue),
								fmt.Sprintf("%.2f", lower2LimitValue),
								fmt.Sprintf("%.2f", rangeUpperValue),
								fmt.Sprintf("%.2f", rangeLowerValue),
								fmt.Sprintf("%d", shield),
								fmt.Sprintf("%d", alertBit),
								fmt.Sprintf("%d", formula),
								fmt.Sprintf("%d", diagMode),
							})
							tmp := &FrameItem{
								Code1:            code1,
								Code2:            code2,
								Code3:            code3,
								Code4:            fmt.Sprintf("%03d", i+1),
								ChannelType:      moduleType,
								Addr:             fmt.Sprintf("%s-%s-%s-%s", code1, code2, code3, fmt.Sprintf("%03d", i+1)),
								UpperLimitValue:  float64(upperLimitValue),
								LowerLimitValue:  float64(lowerLimitValue),
								Upper2LimitValue: float64(upper2LimitValue),
								Lower2LimitValue: float64(lower2LimitValue),
								RangeUpperLimit:  float64(rangeUpperValue),
								RangeLowerLimit:  float64(rangeLowerValue),
								Shield:           FSBoolToNormalBool(shield),
								AlertBit:         FSBoolToNormalBool(alertBit),
								Formula:          formula,
								DiagMode:         diagMode,
							}
							dataPart = append(dataPart, tmp)
						}

						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"通道号", "上限", "下限", "上上限", "下下限", "量程上限", "量程下限", "屏蔽", "报警", "计算公式", "诊断模式"})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						ModuleUploadHandle(fse, moduleType, moduleNumber, code2, code3, dataPart)
						ResponseDo(fse, "0403", str)
					case 0x83:
						ResponseDo(fse, "0483", str)
					case 0x04:
						moduleType := "DI"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0404】 %s模块上载 %s", moduleType, addr)})
						if currentFrameLength < 15 {
							j_log.LogWarning([]interface{}{"0404 数据帧长度小于15,数据帧无效", currentFrameLength})
							continue loop0
						}
						dataPart := make([]*FrameItem, 0)
						moduleNumber := buffer[8]
						channelQuantity := buffer[9]
						contentBytes := buffer[10 : currentFrameLength-5]
						code1 := fse.Code1
						code2 := AllowModuleCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)

						blockLength := 3
						if len(contentBytes) != int(channelQuantity)*blockLength {
							fmt.Printf("[%s ~ %02d%02d]# %s 通道数与实际不匹配\n", tools.GetNow(), funcCode, cmdCode, moduleType)
							continue loop0
						}
						tableData := make([][]string, 0)
						for i := 0; i < int(channelQuantity); i++ {
							shield := contentBytes[i*blockLength]
							shieldTime := tools.BytesToUint16(contentBytes[i*blockLength+1:i*blockLength+3], fse.IntEndian)
							tableData = append(tableData, []string{
								fmt.Sprintf("%03d", i+1),
								fmt.Sprintf("%d", shield),
								fmt.Sprintf("%d", shieldTime),
							})
							tmp := &FrameItem{
								Code1:       code1,
								Code2:       code2,
								Code3:       code3,
								Code4:       fmt.Sprintf("%03d", i+1),
								ChannelType: moduleType,
								Addr:        fmt.Sprintf("%s-%s-%s-%s", code1, code2, code3, fmt.Sprintf("%03d", i+1)),
								Shield:      FSBoolToNormalBool(shield),
								ShieldTime:  int(shieldTime),
							}
							dataPart = append(dataPart, tmp)
						}

						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"通道号", "滤波/脉冲", "滤波/持续时间"})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						ModuleUploadHandle(fse, moduleType, moduleNumber, code2, code3, dataPart)
						ResponseDo(fse, "0404", str)
					case 0x84:
						ResponseDo(fse, "0484", str)
					case 0x05:
						moduleType := "DQ"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0405】 %s模块上载 %s", moduleType, addr)})
						if currentFrameLength < 15 {
							j_log.LogWarning([]interface{}{"0405 数据帧长度小于15,数据帧无效", currentFrameLength})
							continue loop0
						}
						dataPart := make([]*FrameItem, 0)
						moduleNumber := buffer[8]
						channelQuantity := buffer[9]
						contentBytes := buffer[10 : currentFrameLength-5]
						code1 := fse.Code1
						code2 := AllowModuleCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)

						blockLength := 3
						if len(contentBytes) != int(channelQuantity)*blockLength {
							fmt.Printf("[%s ~ %02d%02d]# %s 通道数与实际不匹配\n", tools.GetNow(), funcCode, cmdCode, moduleType)
							continue loop0
						}
						tableData := make([][]string, 0)
						for i := 0; i < int(channelQuantity); i++ {
							shield := contentBytes[i*blockLength]
							shieldTime := tools.BytesToUint16(contentBytes[i*blockLength+1:i*blockLength+3], fse.IntEndian)
							tableData = append(tableData, []string{
								fmt.Sprintf("%03d", i+1),
								fmt.Sprintf("%d", shield),
								fmt.Sprintf("%d", shieldTime),
							})
							tmp := &FrameItem{
								Code1:       code1,
								Code2:       code2,
								Code3:       code3,
								Code4:       fmt.Sprintf("%03d", i+1),
								ChannelType: moduleType,
								Addr:        fmt.Sprintf("%s-%s-%s-%s", code1, code2, code3, fmt.Sprintf("%03d", i+1)),
								Shield:      FSBoolToNormalBool(shield),
								ShieldTime:  int(shieldTime),
							}
							dataPart = append(dataPart, tmp)
						}

						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"通道号", "滤波/脉冲", "滤波/持续时间"})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						ModuleUploadHandle(fse, moduleType, moduleNumber, code2, code3, dataPart)
						ResponseDo(fse, "0405", str)
					case 0x85:
						ResponseDo(fse, "0485", str)
					case 0x06:
						moduleType := "Other"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0406】 %s模块上载 %s", moduleType, addr)})
						if currentFrameLength < 15 {
							j_log.LogWarning([]interface{}{"0406 数据帧长度小于15,数据帧无效", currentFrameLength})
							continue loop0
						}

						dataPart := make([]*FrameItem, 0)
						moduleNumber := buffer[8]
						channelQuantity := buffer[9]
						contentBytes := buffer[10 : currentFrameLength-5]
						code1 := fse.Code1
						code2 := AllowModuleCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						/*--- Other 解析 start ---*/
						blockNum := 0
						blockAIAQLength := 28
						blockDIDQLength := 3
						i := 0 // 当前字节位置
						tableData := make([][]string, 0)
						for {
							if i >= len(contentBytes) {
								if blockNum != int(channelQuantity) {
									fmt.Printf("[%s ~ %02d%02d]# %s 通道数与实际不匹配\n", tools.GetNow(), funcCode, cmdCode, moduleType)
									continue loop0
								}
								break
							}
							realModuleType := "AI"
							channelType := contentBytes[i]
							if channelType == 0x01 || channelType == 0x02 {
								if channelType == 0x01 {
									realModuleType = "AI"
								} else {
									realModuleType = "AQ"
								}
								i++
								if i+blockAIAQLength > len(contentBytes) {
									fmt.Printf("[%s ~ %02d%02d]# %s Other字节内容即将超出blockAIAQLength\n", tools.GetNow(), funcCode, cmdCode, moduleType)
									continue loop0
								}
								upperLimitValue := tools.BytesToFloat32(contentBytes[i:i+4], fse.FloatEndian)
								i += 4
								lowerLimitValue := tools.BytesToFloat32(contentBytes[i:i+4], fse.FloatEndian)
								i += 4
								upper2LimitValue := tools.BytesToFloat32(contentBytes[i:i+4], fse.FloatEndian)
								i += 4
								lower2LimitValue := tools.BytesToFloat32(contentBytes[i:i+4], fse.FloatEndian)
								i += 4
								rangeUpperValue := tools.BytesToFloat32(contentBytes[i:i+4], fse.FloatEndian)
								i += 4
								rangeLowerValue := tools.BytesToFloat32(contentBytes[i:i+4], fse.FloatEndian)
								i += 4
								shield := contentBytes[i]
								i++
								alertBit := contentBytes[i]
								i++
								formula := contentBytes[i]
								i++
								diagMode := contentBytes[i]
								i++
								tableData = append(tableData, []string{
									fmt.Sprintf("%03d", blockNum+1),
									fmt.Sprintf("%#02x", channelType),
									fmt.Sprintf("%.2f", upperLimitValue),
									fmt.Sprintf("%.2f", lowerLimitValue),
									fmt.Sprintf("%.2f", upper2LimitValue),
									fmt.Sprintf("%.2f", lower2LimitValue),
									fmt.Sprintf("%.2f", rangeUpperValue),
									fmt.Sprintf("%.2f", rangeLowerValue),
									fmt.Sprintf("%d", shield),
									fmt.Sprintf("%d", alertBit),
									fmt.Sprintf("%d", formula),
									fmt.Sprintf("%d", diagMode),
								})
								tmp := &FrameItem{
									Code1:            code1,
									Code2:            code2,
									Code3:            code3,
									Code4:            fmt.Sprintf("%03d", blockNum+1),
									ChannelType:      realModuleType,
									Addr:             fmt.Sprintf("%s-%s-%s-%s", code1, code2, code3, fmt.Sprintf("%03d", blockNum+1)),
									UpperLimitValue:  float64(upperLimitValue),
									LowerLimitValue:  float64(lowerLimitValue),
									Upper2LimitValue: float64(upper2LimitValue),
									Lower2LimitValue: float64(lower2LimitValue),
									RangeUpperLimit:  float64(rangeUpperValue),
									RangeLowerLimit:  float64(rangeLowerValue),
									Shield:           FSBoolToNormalBool(shield),
									AlertBit:         FSBoolToNormalBool(alertBit),
									Formula:          formula,
									DiagMode:         diagMode,
								}
								dataPart = append(dataPart, tmp)
								blockNum++
							} else if channelType == 0x03 || channelType == 0x04 {
								if channelType == 0x03 {
									realModuleType = "DI"
								} else {
									realModuleType = "DQ"
								}
								i++
								if i+blockDIDQLength > len(contentBytes) {
									fmt.Printf("[%s ~ %02d%02d]# %s 字节内容即将超出blockDIDQLength\n", tools.GetNow(), funcCode, cmdCode, moduleType)
									continue loop0
								}
								shield := contentBytes[i]
								i++
								shieldTime := tools.BytesToUint16(contentBytes[i:i+2], fse.IntEndian)
								i += 2
								tableData = append(tableData, []string{
									fmt.Sprintf("%03d", blockNum+1),
									fmt.Sprintf("%#02x", channelType),
									fmt.Sprintf("%d", shield),
									fmt.Sprintf("%d", shieldTime),
								})

								tmp := &FrameItem{
									Code1:       code1,
									Code2:       code2,
									Code3:       code3,
									Code4:       fmt.Sprintf("%03d", blockNum+1),
									ChannelType: realModuleType,
									Addr:        fmt.Sprintf("%s-%s-%s-%s", code1, code2, code3, fmt.Sprintf("%03d", blockNum+1)),
									Shield:      FSBoolToNormalBool(shield),
									ShieldTime:  int(shieldTime),
								}
								dataPart = append(dataPart, tmp)

								blockNum++

							} else {
								fmt.Printf("[%s ~ %02d%02d]# %s 模块无效的通道类型 i=%d,t=%02d\n", tools.GetNow(), funcCode, cmdCode, moduleType, i, channelType)
								continue loop0
							}
						}

						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"通道号", "通道类型", "上限", "下限", "上上限", "下下限", "量程上限", "量程下限", "屏蔽", "报警", "计算公式", "诊断模式"})
						table.Append([]string{"通道号", "通道类型", "滤波/脉冲选择", "滤波/持续时间"})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						/*--- Other 解析 end---*/
						ModuleUploadHandle(fse, moduleType, moduleNumber, code2, code3, dataPart)
						ResponseDo(fse, "0406", str)
					case 0x86:
						ResponseDo(fse, "0486", str)
					}
				case 0x05:
					_ = tools.WriteStringToLog(fmt.Sprintf("[%s~%s]【recv】len=%d#%s", tools.GetNow(), fse.TcpClient.RemoteAddr, n0, str0), "model_upload.log", "a")
					switch cmdCode {
					case 0x01:
						ds := &DataScale{}
						i := 7
						ds.Bengzu = uint8(tools.BytesToUint16(buffer[i:i+2], fse.IntEndian))
						i += 2
						ds.Zengya = uint8(tools.BytesToUint16(buffer[i:i+2], fse.IntEndian))
						i += 2
						ds.Diantiao = uint8(tools.BytesToUint16(buffer[i:i+2], fse.IntEndian))
						i += 2
						ds.Pressure = uint8(tools.BytesToUint16(buffer[i:i+2], fse.IntEndian))
						i += 2
						ds.Power = uint8(tools.BytesToUint16(buffer[i:i+2], fse.IntEndian))
						i += 2
						ds.PowerState = uint8(tools.BytesToUint16(buffer[i:i+2], fse.IntEndian))
						i += 2
						ds.ModeCollect = uint8(tools.BytesToUint16(buffer[i:i+2], fse.IntEndian))
						i += 2
						ds.Diag = uint8(tools.BytesToUint16(buffer[i:i+2], fse.IntEndian))
						i += 2
						ds.EData = tools.BytesToUint16(buffer[i:i+2], fse.IntEndian)
						fmt.Printf("数据规模: 泵组=%d, 增压泵=%d, 电调阀=%d, 压力=%d, 电源控制=%d,电源状态=%d,模态收集=%d,故障诊断=%d, EData=%d\n",
							ds.Bengzu, ds.Zengya, ds.Diantiao, ds.Pressure, ds.Power, ds.PowerState, ds.ModeCollect, ds.Diag, ds.EData)
						TempFSMap.UpdateDS(fse.ID, ds, "model")
						ResponseDo(fse, "0501", str)
						fse.DSModelRead = time.Now().Unix()
					case 0x81:
						ResponseDo(fse, "0581", str)
					case 0x02:
						moduleType := "泵组电磁阀"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0502】 %s模型上载 %s", moduleType, addr)})
						m := ParseModel0502(fse, buffer[8:currentFrameLength-5], fse.Code1)
						tableData := make([][]string, 0)
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "开控制"),
							fmt.Sprintf("%d", m.BengzuStartControlValue),
							fmt.Sprintf("%s", "关控制"),
							fmt.Sprintf("%d", m.BengzuStopControlValue),
							fmt.Sprintf("%s", "开状态"),
							fmt.Sprintf("%d", m.BengzuStartStateValue),
							fmt.Sprintf("%s", "关状态"),
							fmt.Sprintf("%d", m.BengzuStopStateValue),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "连锁"),
							fmt.Sprintf("%d", m.LiansuoValue),
							fmt.Sprintf("%s", "远程就地"),
							fmt.Sprintf("%d", m.RemoteLocalValue),
							fmt.Sprintf("%s", "控制方法"),
							fmt.Sprintf("%d", m.ControlMethodValue),
							fmt.Sprintf("%s", "参数一"),
							fmt.Sprintf("%.2f", m.BengzuParam1Value),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "参数2"),
							fmt.Sprintf("%.2f", m.BengzuParam2Value),
							fmt.Sprintf("%s", "参数3"),
							fmt.Sprintf("%.2f", m.BengzuParam3Value),
							fmt.Sprintf("%s", "参数4"),
							fmt.Sprintf("%.2f", m.BengzuParam4Value),
							fmt.Sprintf("%s", "参数5"),
							fmt.Sprintf("%.2f", m.BengzuParam5Value),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "泵前-启动控制"),
							fmt.Sprintf("%s", m.BengqianStartControl),
							fmt.Sprintf("%s", "泵前-停止控制"),
							fmt.Sprintf("%s", m.BengqianStopControl),
							fmt.Sprintf("%s", "泵前-启动状态"),
							fmt.Sprintf("%s", m.BengqianStartState),
							fmt.Sprintf("%s", "泵前-停止状态"),
							fmt.Sprintf("%s", m.BengqianStopState),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "罗茨泵-启动控制"),
							fmt.Sprintf("%s", m.QianjibengStartControl),
							fmt.Sprintf("%s", "罗茨泵-停止控制"),
							fmt.Sprintf("%s", m.QianjibengStopControl),
							fmt.Sprintf("%s", "罗茨泵-启动状态"),
							fmt.Sprintf("%s", m.QianjibengStartState),
							fmt.Sprintf("%s", "罗茨泵-停止状态"),
							fmt.Sprintf("%s", m.QianjibengStopState),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "前级泵-启动控制"),
							fmt.Sprintf("%s", m.LuocibengStartControl),
							fmt.Sprintf("%s", "前级泵-停止控制"),
							fmt.Sprintf("%s", m.LuocibengStopControl),
							fmt.Sprintf("%s", "前级泵-启动状态"),
							fmt.Sprintf("%s", m.LuocibengStartState),
							fmt.Sprintf("%s", "前级泵-停止状态"),
							fmt.Sprintf("%s", m.LuocibengStopState),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "泵前压力"),
							fmt.Sprintf("%s", m.BengqianPressure),
							fmt.Sprintf("%s", "远程/就地"),
							fmt.Sprintf("%s", m.RemoteLocal), "", "", "", "",
						})

						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"", "", "", "", "", "", "", ""})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						moduleNumber := buffer[6]
						code2 := AllowModelCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						ModelUploadHandle(fse, moduleType, moduleNumber, code2, code3, m)
						ResponseDo(fse, "0502", str)
					case 0x82:
						ResponseDo(fse, "0582", str)
					case 0x03:
						moduleType := "增压泵电磁阀"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0503】 %s模型上载 %s", moduleType, addr)})
						m := ParseModel0503(buffer[8:currentFrameLength-5], fse.Code1)
						tableData := make([][]string, 0)
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "连锁"),
							fmt.Sprintf("%d", m.LiansuoValue),
							fmt.Sprintf("%s", "远程就地"),
							fmt.Sprintf("%s", m.RemoteLocal),
							fmt.Sprintf("%s", "控制方法"),
							fmt.Sprintf("%d", m.ControlMethodValue),
							fmt.Sprintf("%s", "泵前压力"),
							fmt.Sprintf("%s", m.BengqianPressure),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "泵前-启动控制"),
							fmt.Sprintf("%s", m.BengqianStartControl),
							fmt.Sprintf("%s", "泵前-停止控制"),
							fmt.Sprintf("%s", m.BengqianStopControl),
							fmt.Sprintf("%s", "泵前-启动状态"),
							fmt.Sprintf("%s", m.BengqianStartState),
							fmt.Sprintf("%s", "泵前-停止状态"),
							fmt.Sprintf("%s", m.BengqianStopState),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "增压泵-启动控制"),
							fmt.Sprintf("%s", m.ZengyaStartControl),
							fmt.Sprintf("%s", "增压泵-停止控制"),
							fmt.Sprintf("%s", m.ZengyaStopControl),
							fmt.Sprintf("%s", "增压泵-启动状态"),
							fmt.Sprintf("%s", m.ZengyaStartState),
							fmt.Sprintf("%s", "增压泵-停止状态"),
							fmt.Sprintf("%s", m.ZengyaStopState),
						})
						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"", "", "", "", "", "", "", ""})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						moduleNumber := buffer[6]
						code2 := AllowModelCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						ModelUploadHandle(fse, moduleType, moduleNumber, code2, code3, m)
						ResponseDo(fse, "0503", str)
					case 0x83:
						ResponseDo(fse, "0583", str)
					case 0x04:
						moduleType := "电调阀"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0504】 %s模型上载 %s", moduleType, addr)})
						m := ParseModel0504(buffer[8:currentFrameLength-5], fse.Code1)
						tableData := make([][]string, 0)
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "当前开度"),
							fmt.Sprintf("%s", m.CurrentKaidu),
							fmt.Sprintf("%s", "设置开度"),
							fmt.Sprintf("%s", m.SetKaidu),
							fmt.Sprintf("%s", "控制"),
							fmt.Sprintf("%s", m.Control),
							fmt.Sprintf("%s", "设置步长"),
							fmt.Sprintf("%s", m.SetStep),
						})

						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "自检控制"),
							fmt.Sprintf("%s", m.SelfInspection),
							fmt.Sprintf("%s", "上调"),
							fmt.Sprintf("%s", m.Up),
							fmt.Sprintf("%s", "下调"),
							fmt.Sprintf("%s", m.Down),
							fmt.Sprintf("%s", "全开"),
							fmt.Sprintf("%s", m.AllOn),
						})

						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "全关"),
							fmt.Sprintf("%s", m.AllOff),
							fmt.Sprintf("%s", "全开状态"),
							fmt.Sprintf("%s", m.AllOnState),
							fmt.Sprintf("%s", "全关状态"),
							fmt.Sprintf("%s", m.AllOffState),
							fmt.Sprintf("%s", "前级压力"),
							fmt.Sprintf("%s", m.QianjiPressure),
						})

						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "后级压力"),
							fmt.Sprintf("%s", m.HoujiPressure),
							fmt.Sprintf("%s", "目标压力"),
							fmt.Sprintf("%s", m.DestPressure),
							fmt.Sprintf("%s", "P"),
							fmt.Sprintf("%s", m.P),
							fmt.Sprintf("%s", "I"),
							fmt.Sprintf("%s", m.I),
						})

						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "D"),
							fmt.Sprintf("%s", m.D),
							fmt.Sprintf("%s", "自整定-启动控制"),
							fmt.Sprintf("%s", m.CustomStartControl),
							fmt.Sprintf("%s", "自整定-停止控制"),
							fmt.Sprintf("%s", m.CustomStopControl),
							fmt.Sprintf("%s", "自整定-启动状态"),
							fmt.Sprintf("%s", m.CustomStartState),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "自整定-停止状态"),
							fmt.Sprintf("%s", m.CustomStopState),
							fmt.Sprintf("%s", "PID"),
							fmt.Sprintf("%s", m.PID),
							fmt.Sprintf("%s", "远程就地"),
							fmt.Sprintf("%s", m.RemoteLocal),
							fmt.Sprintf("%s", "控制方法"),
							fmt.Sprintf("%s", m.ControlMethod),
						})

						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"", "", "", "", "", "", "", ""})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						moduleNumber := buffer[6]
						code2 := AllowModelCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						ModelUploadHandle(fse, moduleType, moduleNumber, code2, code3, m)
						ResponseDo(fse, "0504", str)
					case 0x84:
						ResponseDo(fse, "0584", str)
					case 0x05:
						moduleType := "压力电磁阀"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0505】 %s模型上载 %s", moduleType, addr)})
						m := ParseModel0505(buffer[8:currentFrameLength-5], fse.Code1)
						tableData := make([][]string, 0)
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "连锁"),
							fmt.Sprintf("%d", m.LiansuoValue),
							fmt.Sprintf("%s", "控制方法"),
							fmt.Sprintf("%d", m.ControlMethodValue),
							fmt.Sprintf("%s", "压力"),
							fmt.Sprintf("%s", m.Pressure),
							"", "",
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "电磁阀-启动控制"),
							fmt.Sprintf("%s", m.SVStartControl),
							fmt.Sprintf("%s", "电磁阀-停止控制"),
							fmt.Sprintf("%s", m.SVStopControl),
							fmt.Sprintf("%s", "电磁阀-启动状态"),
							fmt.Sprintf("%s", m.SVStartState),
							fmt.Sprintf("%s", "电磁阀-停止状态"),
							fmt.Sprintf("%s", m.SVStopState),
						})
						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"", "", "", "", "", "", "", ""})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						moduleNumber := buffer[6]
						code2 := AllowModelCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						ModelUploadHandle(fse, moduleType, moduleNumber, code2, code3, m)
						ResponseDo(fse, "0505", str)
					case 0x85:
						ResponseDo(fse, "0585", str)
					case 0x06:
						moduleType := "电源控制"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0506】 %s模型上载 %s", moduleType, addr)})
						if len(buffer) != 80 {
							j_log.LogError([]interface{}{fmt.Sprintf("帧长度异常, 当前长度 %d", len(buffer))})
							continue loop0
						}
						m, err2 := ParseModel0506(fse, buffer[8:currentFrameLength-5])
						if err2 != nil {
							j_log.LogError([]interface{}{fmt.Sprintf("%s", err2.Error())})
							continue loop0
						}
						tableData := make([][]string, 0)
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "PLC类型"),
							fmt.Sprintf("%d", m.PLCType),
							fmt.Sprintf("%s", "IP"),
							fmt.Sprintf("%s", m.IP),
							fmt.Sprintf("%s", "端口"),
							fmt.Sprintf("%d", m.Port),
							"",
							"",
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "U1块"),
							fmt.Sprintf("%d", m.U1BlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.U1AddrValue),
							fmt.Sprintf("%s", "U2块"),
							fmt.Sprintf("%d", m.U2BlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.U2AddrValue),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "U3块"),
							fmt.Sprintf("%d", m.U3BlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.U3AddrValue),
							fmt.Sprintf("%s", "I1块"),
							fmt.Sprintf("%d", m.I1BlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.I1AddrValue),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "I2块"),
							fmt.Sprintf("%d", m.I2BlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.I2AddrValue),
							fmt.Sprintf("%s", "I3块"),
							fmt.Sprintf("%d", m.I3BlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.I3AddrValue),
						})

						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "F块"),
							fmt.Sprintf("%d", m.FBlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.FAddrValue),
							fmt.Sprintf("%s", "有功功率块"),
							fmt.Sprintf("%d", m.ActivePowerBlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.ActivePowerAddrValue),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "无功功率块"),
							fmt.Sprintf("%d", m.ReactivePowerBlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.ReactivePowerAddrValue),
							fmt.Sprintf("%s", "视在功率块"),
							fmt.Sprintf("%d", m.ApparentPowerBlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.ApparentPowerAddrValue),
						})
						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"", "", "", "", "", "", "", ""})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						moduleNumber := buffer[6]
						code2 := AllowModelCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						ModelUploadHandle(fse, moduleType, moduleNumber, code2, code3, m)
						ResponseDo(fse, "0506", str)
					case 0x86:
						ResponseDo(fse, "0586", str)
					case 0x07:
						moduleType := "电源状态"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0507】 %s模型上载 %s", moduleType, addr)})
						if len(buffer) != 32 {
							j_log.LogError([]interface{}{fmt.Sprintf("帧长度异常, 当前长度 %d", len(buffer))})
							continue loop0
						}
						m, err2 := ParseModel0507(fse, buffer[8:currentFrameLength-5])
						if err2 != nil {
							j_log.LogError([]interface{}{fmt.Sprintf(err2.Error())})
							continue loop0
						}
						tableData := make([][]string, 0)
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "PLC类型"),
							fmt.Sprintf("%d", m.PLCType),
							fmt.Sprintf("%s", "IP:PORT"),
							fmt.Sprintf("%s:%d", m.IP, m.Port),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "运行状态块"),
							fmt.Sprintf("%d", m.RunningStateBlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.RunningStateAddrValue),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "故障状态块"),
							fmt.Sprintf("%d", m.ErrorStateBlockValue),
							fmt.Sprintf("%s", "地址"),
							fmt.Sprintf("%s", m.ErrorStateAddrValue),
						})
						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"", "", "", ""})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						moduleNumber := buffer[6]
						code2 := AllowModelCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						ModelUploadHandle(fse, moduleType, moduleNumber, code2, code3, m)
						ResponseDo(fse, "0507", str)
					case 0x87:
						ResponseDo(fse, "0587", str)
					case 0x08:
						moduleType := "模态采集"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0508】 %s模型上载 %s", moduleType, addr)})
						m := ParseModel0508(buffer[8:currentFrameLength-5], fse.Code1)
						tableData := make([][]string, 0)
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "激励点位"),
							fmt.Sprintf("%s", m.StimulatePoint),
							fmt.Sprintf("%s", "响应点位"),
							fmt.Sprintf("%s", m.ResponsePoint),
							fmt.Sprintf("%s", "开控制"),
							fmt.Sprintf("%s", m.StartControl),
							fmt.Sprintf("%s", "关控制"),
							fmt.Sprintf("%s", m.StopControl),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "开状态"),
							fmt.Sprintf("%s", m.StartState),
							fmt.Sprintf("%s", "关状态"),
							fmt.Sprintf("%s", m.StopState),
							"", "", "", "",
						})
						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"", "", "", "", "", "", "", ""})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						moduleNumber := buffer[6]
						code2 := AllowModelCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						ModelUploadHandle(fse, moduleType, moduleNumber, code2, code3, m)
						ResponseDo(fse, "0508", str)
					case 0x88:
						ResponseDo(fse, "0588", str)
					case 0x09:
						moduleType := "故障诊断"
						j_log.LogInfo([]interface{}{fmt.Sprintf("【指令0509】 %s模型上载 %s", moduleType, addr)})
						m := ParseModel0509(fse, buffer[8:currentFrameLength-5], fse.Code1)
						tableData := make([][]string, 0)
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "诊断模式"),
							fmt.Sprintf("%.2f", m.DiagModeValue),
							fmt.Sprintf("%s", "诊断参数1"),
							fmt.Sprintf("%.2f", m.DiagParam1Value),
							fmt.Sprintf("%s", "诊断参数2"),
							fmt.Sprintf("%.2f", m.DiagParam2Value),
							fmt.Sprintf("%s", "诊断参数3"),
							fmt.Sprintf("%.2f", m.DiagParam3Value),
						})
						tableData = append(tableData, []string{
							fmt.Sprintf("%s", "诊断参数4"),
							fmt.Sprintf("%.2f", m.DiagParam4Value),
							fmt.Sprintf("%s", "诊断参数5"),
							fmt.Sprintf("%.2f", m.DiagParam5Value),
							"", "", "", "",
						})
						table := tablewriter.NewWriter(os.Stdout)
						table.SetHeader([]string{"", "", "", "", "", "", "", ""})
						for _, v := range tableData {
							table.Append(v)
						}
						table.Render()
						moduleNumber := buffer[6]
						code2 := AllowModelCode2[moduleType]
						code3 := fmt.Sprintf("%02d", moduleNumber)
						ModelUploadHandle(fse, moduleType, moduleNumber, code2, code3, m)
						ResponseDo(fse, "0509", str)
					case 0x89:
						ResponseDo(fse, "0589", str)
					}
				case 0x06:
					switch cmdCode {
					case 0x01:
						ds := &DataScale{}
						i := 7
						ds.AI = buffer[i]
						i++
						ds.DI = buffer[i]
						i++
						ds.AQ = buffer[i]
						i++
						ds.DQ = buffer[i]
						i++
						ds.Other = buffer[i]
						i++
						ds.EData = tools.BytesToUint16(buffer[i:i+2], fse.IntEndian)
						i += 2
						ds.Bengzu = buffer[i]
						i++
						ds.Zengya = buffer[i]
						i++
						ds.Pressure = buffer[i]
						i++
						fmt.Printf("数据规模: AI=%d, DI=%d, AQ=%d, DQ=%d, Other=%d, EData=%d, 泵组电磁阀=%d, 增压泵电磁阀=%d, 压力电磁阀=%d\n",
							ds.AI, ds.DI, ds.AQ, ds.DQ, ds.Other, ds.EData, ds.Bengzu, ds.Zengya, ds.Pressure)
						ResponseDo(fse, "0601", str)
						go func(fse *FSEquip) {
							data := GenFSFrameData0602()
							_, err = fse.Write(data)
							if err != nil {
								j_log.LogError([]interface{}{"首次运行同步tcp发送失败", fse.Name, fse.IP, fse.Port, err.Error()})
								return
							}
							j_log.LogInfo([]interface{}{"首次运行同步tcp发送成功", fse.Name, fse.IP, fse.Port})
						}(fse)
					case 0x81:
						ResponseDo(fse, "0681", str)
					case 0x02:
						fsTmp, err1 := Data0602Parse(fse, funcCode, cmdCode, buffer[0:currentFrameLength], currentFrameLength)
						if err1 != nil {
							j_log.LogError([]interface{}{"Data0602Parse", err1.Error(), str})
							continue loop0
						}
						cmd := fmt.Sprintf("%02d%02d", funcCode, cmdCode)
						if fsTmp != nil {
							if fsTmp.DS.AI != fse.DS.AI ||
								fsTmp.DS.AQ != fse.DS.AQ ||
								fsTmp.DS.DI != fse.DS.DI ||
								fsTmp.DS.DQ != fse.DS.DQ ||
								fsTmp.DS.Other != fse.DS.Other ||
								fsTmp.DS.Bengzu != fse.DS.Bengzu ||
								fsTmp.DS.Zengya != fse.DS.Zengya ||
								fsTmp.DS.Pressure != fse.DS.Pressure {
								fse.DSMatched = 0
								j_log.LogError([]interface{}{"WARNING 数据规模不一致, 记录报警"})
								_ = SysAlertSave(&SysAlert{
									ProjectID: fse.ProjectID,
									Const:     "ALERT_FS",
									Alert:     fse.Name + " 自研设备数据大规模不一致",
									Detail: fmt.Sprintf("设备规模: AI=%d, DI=%d, AQ=%d, DQ=%d, Other=%d, EData=%d, 泵组电磁阀=%d, 增压泵电磁阀=%d, 压力电磁阀=%d\n",
										fsTmp.DS.AI, fsTmp.DS.DI, fsTmp.DS.AQ, fsTmp.DS.DQ, fsTmp.DS.Other, fsTmp.DS.EData, fsTmp.DS.Bengzu, fsTmp.DS.Zengya, fsTmp.DS.Pressure) +
										fmt.Sprintf("本地规模: AI=%d, DI=%d, AQ=%d, DQ=%d, Other=%d, EData=%d, 泵组电磁阀=%d, 增压泵电磁阀=%d, 压力电磁阀=%d\n",
											fse.DS.AI, fse.DS.DI, fse.DS.AQ, fse.DS.DQ, fse.DS.Other, fse.DS.EData, fse.DS.Bengzu, fse.DS.Zengya, fse.DS.Pressure),
									RelationID: fse.ID,
								})

								ResponseDo(fse, cmd, "不一致")
							} else {
								for _, module := range fse.FSModule {
									for _, tmpModule := range fsTmp.FSModule {
										if AllowModuleCode2[module.ModuleType] != "" && module.Code2 == tmpModule.Code2 && module.Code3 == tmpModule.Code3 {
											validN := 0
											for _, row := range module.FrameItem {
												if len(row.Addr) == 12 {
													validN++
												}
											}
											if validN != len(tmpModule.FrameItem) {
												msg := fmt.Sprintf("模块【%s】 数据规模不一致", module.ModuleType)
												j_log.LogError([]interface{}{msg})
												_ = SysAlertSave(&SysAlert{
													ProjectID:  fse.ProjectID,
													Const:      "ALERT_FS",
													Alert:      fse.Name + " 自研设备数据规模不一致;" + msg,
													Detail:     "",
													RelationID: fse.ID,
												})
												ResponseDo(fse, cmd, msg)
												continue loop0
											}

											//json1, _ := json.MarshalIndent(module, "", "  ")
											//json2, _ := json.MarshalIndent(tmpModule, "", "  ")
											//_ = tools.WriteStringToFile(string(json1), "module.json", "w")
											//_ = tools.WriteStringToFile(string(json2), "tmpModule.json", "w")
											if module.ModuleType == "Other" {
												for _, tmpItem := range tmpModule.FrameItem {
													matched := false
													for _, item := range module.FrameItem {
														if len(item.Addr) == 12 && item.Code4 == tmpItem.Code4 {
															matched = true
															itemNew, ok := VariablesMap.Get(item.Addr)
															if !ok {
																msg := fmt.Sprintf("【%s】Exception 未找到内存变量", item.Addr)
																j_log.LogError([]interface{}{msg})
																ResponseDo(fse, cmd, msg)
																continue loop0
															}
															item.ChannelType = itemNew.ChannelType // 使用内存中最新的channel_type对比
															if item.ChannelType != tmpItem.ChannelType {
																msg := fmt.Sprintf("【%s-%s-%s】通道类型不一致", module.ModuleType, item.Code3, item.Code4)
																_ = SysAlertSave(&SysAlert{
																	ProjectID:  fse.ProjectID,
																	Const:      "ALERT_FS",
																	Alert:      fse.Name + " 自研设备数据规模不一致;" + msg,
																	Detail:     "",
																	RelationID: fse.ID,
																})
																j_log.LogError([]interface{}{msg})
																ResponseDo(fse, cmd, msg)
																continue loop0
															}
															break
														}
													}
													if !matched {
														msg := fmt.Sprintf("【%s-%s-%s】通道未匹配", module.ModuleType, tmpItem.Code3, tmpItem.Code4)
														_ = SysAlertSave(&SysAlert{
															ProjectID:  fse.ProjectID,
															Const:      "ALERT_FS",
															Alert:      fse.Name + " 自研设备数据规模不一致;" + msg,
															Detail:     "",
															RelationID: fse.ID,
														})
														j_log.LogError([]interface{}{msg})
														ResponseDo(fse, cmd, msg)
														continue loop0
													}
												}
											}
										}
									}
								}
								fse.DSMatched = 1
								ResponseDo(fse, cmd, "ok")
								j_log.LogInfo([]interface{}{"数据规模一致, 自动循环运行同步了"})
							}
						}
					case 0x12:
						//j_log.LogInfo([]interface{}{"todo todo =============================== 运行同步限值部分, 有真实帧数据时再开发"})
						ResponseDo(fse, "0612", str)
					case 0x03:
						err = Data0603Parse(fse, funcCode, cmdCode, buffer[0:currentFrameLength], currentFrameLength)
						if err != nil {
							j_log.LogError([]interface{}{err})
							continue loop0
						}
					case 0x83:
						j_log.LogInfo([]interface{}{"运行同步限值部分, 有真实帧数据时再开发"})
						ResponseDo(fse, "0683", str)
					case 0x82:
						ResponseDo(fse, "0682", str)
					case 0x04:
						j_log.LogInfo([]interface{}{"0604", str})
						err = Data0603Parse(fse, funcCode, cmdCode, buffer[0:currentFrameLength], currentFrameLength)
						if err != nil {
							j_log.LogError([]interface{}{err})
							continue loop0
						}
					case 0x84:
						ResponseDo(fse, "0684", str)
					case 0x05:
						ResponseDo(fse, "0605", str)
					case 0x85:
						ResponseDo(fse, "0685", str)
					}
				default:
					j_log.LogError([]interface{}{"暂不支持的功能码", funcCode})
				}
				if n0 == int(length) {
					break
				}
				buffer = resetRawData(buffer, currentFrameLength)
				if len(buffer) == 0 {
					break
				}
				if len(buffer) < 6 {
					j_log.LogError([]interface{}{"Exception next数据帧长度小于6", fse.Name, addr})
					break
				}
			}
		}
		// 清空buffer
		//for i := 0; i < n0; i++ {
		//	buffer[i] = 0
		//}
	}
}

func (fse *FSEquip) tcpErrorHandle(err error) {
	if err == io.EOF {
		fse.Detail = "远程连接已关闭."
		j_log.LogError([]interface{}{"远程连接已关闭.", fse.Name})
	} else if strings.Contains(err.Error(), "No connection could be made because the target machine actively refused it") {
		fse.Detail = "server连接失败.目标计算机积极拒绝."
		j_log.LogError([]interface{}{"server连接失败.目标计算机积极拒绝", fse.Name})
	} else if strings.Contains(err.Error(), "was forcibly closed by the remote host") {
		fse.Detail = "远程连接已关闭."
		j_log.LogError([]interface{}{"远程连接已关闭..", fse.Name})
	} else if err == net.ErrClosed || strings.Contains(err.Error(), "use of closed network connection") || strings.Contains(err.Error(), "read: connection reset by peer") || strings.Contains(err.Error(), "closed by the remote host") {
		fse.Detail = "连接已关闭或重置"
		j_log.LogError([]interface{}{"连接已关闭或重置", fse.Name})
	} else {
		fse.Detail = "连接服务端失败"
		j_log.LogError([]interface{}{"连接服务端失败", fse.Name, err.Error()})
	}
}

func resetRawData(rawData []byte, toIndex int) []byte {
	if len(rawData) > toIndex {
		rawData = rawData[toIndex:]
	} else {
		rawData = make([]byte, 0)
	}
	return rawData
}
func Data0602Parse(fse *FSEquip, funcCode, cmdCode byte, buffer []byte, n int) (fsTmp *FSEquip, err error) {
	defer func() {
		if err2 := recover(); err2 != nil {
			j_log.LogError([]interface{}{"Data0602Parse panic", err2})
			fmt.Println(string(debug.Stack()))
		}
	}()

	frameCount := buffer[5]
	frameNum := buffer[6]
	//j_log.LogInfo([]interface{}{fmt.Sprintf("%02d%02d运行正常返回 [帧总数=%d][帧序号=%d]", funcCode, cmdCode, frameCount, frameNum)})
	dataPart := buffer[17 : n-5]
	if frameCount >= 1 {
		if frameNum < frameCount {
			fse.TcpClient.FrameCacheMap.Set(funcCode, cmdCode, frameNum, &FrameCache{
				FrameCount: frameCount,
				FrameNum:   frameNum,
				Data:       append([]byte(nil), buffer[17:n-5]...),
				CreateTime: time.Now().Unix(),
			})
		} else if frameNum == frameCount {
			/*--- 接收到全部帧后开始合并数据,并处理 ---*/
			dataPart, err = fse.TcpClient.FrameCacheMap.MergeDataPart0602(funcCode, cmdCode, frameNum, dataPart)
			if err != nil {
				j_log.LogError([]interface{}{"数据合并异常", err.Error()})
				return
			}
			messageList := make([]*QueueValue, 0)
			now := tools.GetNow()
			AICount := buffer[7]
			DICount := buffer[8]
			AQCount := buffer[9]
			DQCount := buffer[10]
			OtherCount := buffer[11]
			BengzuCount := buffer[14]
			ZengyaCount := buffer[15]
			PressureCount := buffer[16]

			fsTmp = &FSEquip{}
			dsTmp := &DataScale{}
			dsTmp.AI = AICount
			dsTmp.DI = DICount
			dsTmp.AQ = AQCount
			dsTmp.DQ = DQCount
			dsTmp.Other = OtherCount
			dsTmp.Bengzu = BengzuCount
			dsTmp.Zengya = ZengyaCount
			dsTmp.Pressure = PressureCount

			//j_log.LogInfo([]interface{}{fmt.Sprintf("合并后数据规模 AICount=%d,DICount=%d,AQCount=%d,DQCount=%d,OtherCount=%d,BengzuCount=%d,ZengyaCount=%d,PressureCount=%d\n",
			//	AICount, DICount, AQCount, DQCount, OtherCount, BengzuCount, ZengyaCount, PressureCount)})
			i := 0
			Display0602(fmt.Sprintf("------ AI Parsing %d\n", i))
			for AINum := 1; AINum <= int(AICount); AINum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("AI%02d=%02d 通道数=%d: \n", AINum, dataPart[i], channelCount))
				i += 2

				tmpModule := &FSModule{}
				tmpModule.ModuleType = "AI"
				tmpModule.Code1 = fse.Code1
				tmpModule.Code2 = AllowFSCode2[tmpModule.ModuleType]
				tmpModule.Code3 = fmt.Sprintf("%02d", AINum)

				for j := 1; j <= int(channelCount); j++ {
					v := tools.BytesToFloat32(dataPart[i:i+4], fse.FloatEndian)
					Display0602(fmt.Sprintf("v%02d=%.2f, ", j, v))
					i += 4
					shieldV := dataPart[i]
					Display0602(fmt.Sprintf("屏蔽%02d=%d, ", j, FSToLocalByte(shieldV)))
					i++
					alertV := dataPart[i]
					Display0602(fmt.Sprintf("报警%02d=%d,\n", j, alertV))
					i++
					addr := GetAddrFromFSE(fse, "AI", AINum, j, "")
					UpdateMemShieldAlert(addr, shieldV, alertV)
					messageList = append(messageList, &QueueValue{
						Addr:       addr,
						Value:      float64(v),
						FSShield:   FSToLocalByte(shieldV),
						FSAlert:    alertV,
						CreateTime: &now,
					})

					tmpModule.FrameItem = append(tmpModule.FrameItem, &FrameItem{
						Code1:       fse.Code1,
						Code2:       tmpModule.Code2,
						Code3:       tmpModule.Code3,
						Code4:       fmt.Sprintf("%03d", j),
						ChannelType: "AI",
						Value:       float64(v),
						CreateTime:  &now,
					})
				}
				fsTmp.FSModule = append(fsTmp.FSModule, tmpModule)
			}

			Display0602(fmt.Sprintf("------ DI Parsing %d\n", i))
			for DINum := 1; DINum <= int(DICount); DINum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("DI%02d=%02d 通道数=%d:  ", DINum, dataPart[i], channelCount))
				i += 2
				tmpModule := &FSModule{}
				tmpModule.ModuleType = "DI"
				tmpModule.Code1 = fse.Code1
				tmpModule.Code2 = AllowFSCode2[tmpModule.ModuleType]
				tmpModule.Code3 = fmt.Sprintf("%02d", DINum)

				for j := 1; j <= int(channelCount); j++ {
					v := dataPart[i]
					Display0602(fmt.Sprintf("v%02d=%d, ", j, v))
					messageList = append(messageList, &QueueValue{
						Addr:       GetAddrFromFSE(fse, "DI", DINum, j, ""),
						Value:      float64(FSToLocalByte(v)),
						CreateTime: &now,
					})
					i++
					tmpModule.FrameItem = append(tmpModule.FrameItem, &FrameItem{
						Code1:       fse.Code1,
						Code2:       tmpModule.Code2,
						Code3:       tmpModule.Code3,
						Code4:       fmt.Sprintf("%03d", j),
						ChannelType: "DI",
						Value:       float64(FSToLocalByte(v)),
						CreateTime:  &now,
					})
				}
				Display0602("\n")
				fsTmp.FSModule = append(fsTmp.FSModule, tmpModule)
			}

			Display0602(fmt.Sprintf("------ AQ Parsing %d\n", i))
			for AQNum := 1; AQNum <= int(AQCount); AQNum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("AQ%02d=%02d 通道数=%d: \n", AQNum, dataPart[i], channelCount))
				i += 2

				tmpModule := &FSModule{}
				tmpModule.ModuleType = "AQ"
				tmpModule.Code1 = fse.Code1
				tmpModule.Code2 = AllowFSCode2[tmpModule.ModuleType]
				tmpModule.Code3 = fmt.Sprintf("%02d", AQNum)

				for j := 1; j <= int(channelCount); j++ {
					v := tools.BytesToFloat32(dataPart[i:i+4], fse.FloatEndian)
					Display0602(fmt.Sprintf("v%02d=%.2f, ", j, v))
					i += 4
					shieldV := dataPart[i]
					Display0602(fmt.Sprintf("屏蔽%02d=%d, ", j, FSToLocalByte(shieldV)))
					i++
					alertV := dataPart[i]
					Display0602(fmt.Sprintf("报警%02d=%d,\n", j, alertV))
					i++
					addr := GetAddrFromFSE(fse, "AQ", AQNum, j, "")
					UpdateMemShieldAlert(addr, shieldV, alertV)
					messageList = append(messageList, &QueueValue{
						Addr:       addr,
						Value:      float64(v),
						FSShield:   FSToLocalByte(shieldV),
						FSAlert:    alertV,
						CreateTime: &now,
					})

					tmpModule.FrameItem = append(tmpModule.FrameItem, &FrameItem{
						Code1:       fse.Code1,
						Code2:       tmpModule.Code2,
						Code3:       tmpModule.Code3,
						Code4:       fmt.Sprintf("%03d", j),
						ChannelType: "AQ",
						Value:       float64(v),
						CreateTime:  &now,
					})
				}
				fsTmp.FSModule = append(fsTmp.FSModule, tmpModule)
			}

			Display0602(fmt.Sprintf("------ DQ Parsing %d\n", i))
			for DQNum := 1; DQNum <= int(DQCount); DQNum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("DQ%02d=%02d 通道数=%d:  ", DQNum, dataPart[i], channelCount))
				i += 2

				tmpModule := &FSModule{}
				tmpModule.ModuleType = "DQ"
				tmpModule.Code1 = fse.Code1
				tmpModule.Code2 = AllowFSCode2[tmpModule.ModuleType]
				tmpModule.Code3 = fmt.Sprintf("%02d", DQNum)

				for j := 1; j <= int(channelCount); j++ {
					v := dataPart[i]
					Display0602(fmt.Sprintf("v%02d=%d, ", j, v))
					messageList = append(messageList, &QueueValue{
						Addr:       GetAddrFromFSE(fse, "DQ", DQNum, j, ""),
						Value:      float64(FSToLocalByte(v)),
						CreateTime: &now,
					})
					i++

					tmpModule.FrameItem = append(tmpModule.FrameItem, &FrameItem{
						Code1:       fse.Code1,
						Code2:       tmpModule.Code2,
						Code3:       tmpModule.Code3,
						Code4:       fmt.Sprintf("%03d", j),
						ChannelType: "DQ",
						Value:       float64(FSToLocalByte(v)),
						CreateTime:  &now,
					})
				}
				Display0602("\n")
				fsTmp.FSModule = append(fsTmp.FSModule, tmpModule)
			}

			Display0602(fmt.Sprintf("------ Other Parsing %d\n", i))
			for OtherNum := 1; OtherNum <= int(OtherCount); OtherNum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("Other%02d=%02d 通道数=%d: \n", OtherNum, dataPart[i], channelCount))
				i += 2

				tmpModule := &FSModule{}
				tmpModule.ModuleType = "Other"
				tmpModule.Code1 = fse.Code1
				tmpModule.Code2 = AllowFSCode2[tmpModule.ModuleType]
				tmpModule.Code3 = fmt.Sprintf("%02d", OtherNum)

				currChannel := 1
				for currChannel <= int(channelCount) {
					channelType := dataPart[i]
					i++
					switch channelType {
					case 0x01: // AI
						v := tools.BytesToFloat32(dataPart[i:i+4], fse.FloatEndian)
						Display0602(fmt.Sprintf("通道类型%02d: v%02d=%.2f,", channelType, currChannel, v))
						i += 4
						shieldV := dataPart[i]
						Display0602(fmt.Sprintf("屏蔽%02d=%d,", currChannel, FSToLocalByte(shieldV)))
						i++
						alertV := dataPart[i]
						Display0602(fmt.Sprintf("报警%02d=%d\n", currChannel, alertV))
						i++
						addr := GetAddrFromFSE(fse, "Other", OtherNum, currChannel, "")
						UpdateMemShieldAlert(addr, shieldV, alertV)
						messageList = append(messageList, &QueueValue{
							Addr:       addr,
							Value:      float64(v),
							FSShield:   FSToLocalByte(shieldV),
							FSAlert:    alertV,
							CreateTime: &now,
						})

						tmpModule.FrameItem = append(tmpModule.FrameItem, &FrameItem{
							Code1:       fse.Code1,
							Code2:       tmpModule.Code2,
							Code3:       tmpModule.Code3,
							Code4:       fmt.Sprintf("%03d", currChannel),
							ChannelType: "AI",
							Value:       float64(v),
							CreateTime:  &now,
						})
					case 0x02: // AQ
						v := tools.BytesToFloat32(dataPart[i:i+4], fse.FloatEndian)
						Display0602(fmt.Sprintf("通道类型%02d: v%02d=%.2f,", channelType, currChannel, v))
						i += 4
						shieldV := dataPart[i]
						Display0602(fmt.Sprintf("屏蔽%02d=%d,", currChannel, FSToLocalByte(shieldV)))
						i++
						alertV := dataPart[i]
						Display0602(fmt.Sprintf("报警%02d=%d\n", currChannel, alertV))
						i++
						messageList = append(messageList, &QueueValue{
							Addr:       GetAddrFromFSE(fse, "Other", OtherNum, currChannel, ""),
							Value:      float64(v),
							FSShield:   FSToLocalByte(shieldV),
							FSAlert:    alertV,
							CreateTime: &now,
						})
						tmpModule.FrameItem = append(tmpModule.FrameItem, &FrameItem{
							Code1:       fse.Code1,
							Code2:       tmpModule.Code2,
							Code3:       tmpModule.Code3,
							Code4:       fmt.Sprintf("%03d", currChannel),
							ChannelType: "AQ",
							Value:       float64(v),
							CreateTime:  &now,
						})
					case 0x03: // DI
						v := dataPart[i]
						Display0602(fmt.Sprintf("通道类型%02d: v%02d=%d\n", channelType, currChannel, v))
						messageList = append(messageList, &QueueValue{
							Addr:       GetAddrFromFSE(fse, "Other", OtherNum, currChannel, ""),
							Value:      float64(FSToLocalByte(v)),
							CreateTime: &now,
						})
						i++

						tmpModule.FrameItem = append(tmpModule.FrameItem, &FrameItem{
							Code1:       fse.Code1,
							Code2:       tmpModule.Code2,
							Code3:       tmpModule.Code3,
							Code4:       fmt.Sprintf("%03d", currChannel),
							ChannelType: "DI",
							Value:       float64(FSToLocalByte(v)),
							CreateTime:  &now,
						})
					case 0x04: // DQ
						v := dataPart[i]
						Display0602(fmt.Sprintf("通道类型%02d: v%02d=%d\n", channelType, currChannel, v))
						messageList = append(messageList, &QueueValue{
							Addr:       GetAddrFromFSE(fse, "Other", OtherNum, currChannel, ""),
							Value:      float64(FSToLocalByte(v)),
							CreateTime: &now,
						})
						i++

						tmpModule.FrameItem = append(tmpModule.FrameItem, &FrameItem{
							Code1:       fse.Code1,
							Code2:       tmpModule.Code2,
							Code3:       tmpModule.Code3,
							Code4:       fmt.Sprintf("%03d", currChannel),
							ChannelType: "DQ",
							Value:       float64(FSToLocalByte(v)),
							CreateTime:  &now,
						})
					default:
						err = errors.New(fmt.Sprintf("Other通道类型异常 channelType=%d, i=%d", channelType, i))
						return
					}
					currChannel++
				}
				fsTmp.FSModule = append(fsTmp.FSModule, tmpModule)
			}

			Display0602(fmt.Sprintf("------ 泵组 Parsing %d\n", i))
			for num := 1; num <= int(BengzuCount); num++ {
				Display0602(fmt.Sprintf("[%d] 泵组序号%02d: ", num, dataPart[i]))
				i++
				Display0602(fmt.Sprintf("开控制%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "开控制"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602(fmt.Sprintf("关控制%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "关控制"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602(fmt.Sprintf("开状态%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "开状态"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602(fmt.Sprintf("关状态%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "关状态"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602(fmt.Sprintf("连锁%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "连锁"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602("\n")
			}

			Display0602(fmt.Sprintf("------ 增压 Parsing %d\n", i))
			for num := 1; num <= int(ZengyaCount); num++ {
				Display0602(fmt.Sprintf("[%d] 增压泵序号%02d: ", num, dataPart[i]))
				i++
				Display0602(fmt.Sprintf("连锁%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "增压泵电磁阀", num, 0, "连锁"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602("\n")
			}

			Display0602(fmt.Sprintf("------ 压力 Parsing %d\n", i))
			for num := 1; num <= int(PressureCount); num++ {
				Display0602(fmt.Sprintf("[%d] 压力电磁阀序号%02d: ", num, dataPart[i]))
				i++
				Display0602(fmt.Sprintf("连锁%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "压力电磁阀", num, 0, "连锁"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602("\n")
			}

			fsTmp.DS = dsTmp
			//go VariablesMap.PushMessageToClients(messageList)
			//cmd := fmt.Sprintf("%02d%02d", funcCode, cmdCode)
			//if cmd != "0602" {
			//	ResponseDo(fse, cmd, "success")
			//}
		} else {
			j_log.LogError([]interface{}{fmt.Sprintf("异常,帧序号大于帧总数 %d > %d", frameNum, frameCount)})
			err = errors.New(fmt.Sprintf("异常,帧序号大于帧总数 %d > %d", frameNum, frameCount))
			return
		}
	}
	return
}
func Data0603Parse(fse *FSEquip, funcCode, cmdCode byte, buffer []byte, n int) (err error) {
	defer func() {
		if err2 := recover(); err2 != nil {
			j_log.LogError([]interface{}{"Data0603Parse panic", err2})
			fmt.Println(string(debug.Stack()))
		}
	}()

	frameCount := buffer[5]
	frameNum := buffer[6]
	//j_log.LogInfo([]interface{}{fmt.Sprintf("%02d%02d运行正常返回 [帧总数=%d][帧序号=%d]", funcCode, cmdCode, frameCount, frameNum)})
	dataPart := buffer[17 : n-5]
	if frameCount >= 1 {
		if frameNum < frameCount {
			fse.TcpClient.FrameCacheMap.Set(funcCode, cmdCode, frameNum, &FrameCache{
				FrameCount: frameCount,
				FrameNum:   frameNum,
				Data:       append([]byte(nil), buffer[17:n-5]...),
				CreateTime: time.Now().Unix(),
			})
		} else if frameNum == frameCount {
			/*--- 接收到全部帧后开始合并数据,并处理 ---*/
			dataPart, err = fse.TcpClient.FrameCacheMap.MergeDataPart0602(funcCode, cmdCode, frameNum, dataPart)
			if err != nil {
				j_log.LogError([]interface{}{"数据合并异常", err.Error()})
				return
			}
			messageList := make([]*QueueValue, 0)
			now := tools.GetNow()
			AICount := buffer[7]
			DICount := buffer[8]
			AQCount := buffer[9]
			DQCount := buffer[10]
			OtherCount := buffer[11]
			BengzuCount := buffer[14]
			ZengyaCount := buffer[15]
			PressureCount := buffer[16]

			dsTmp := &DataScale{}
			dsTmp.AI = AICount
			dsTmp.DI = DICount
			dsTmp.AQ = AQCount
			dsTmp.DQ = DQCount
			dsTmp.Other = OtherCount
			dsTmp.Bengzu = BengzuCount
			dsTmp.Zengya = ZengyaCount
			dsTmp.Pressure = PressureCount

			//j_log.LogInfo([]interface{}{fmt.Sprintf("合并后数据规模 AICount=%d,DICount=%d,AQCount=%d,DQCount=%d,OtherCount=%d,BengzuCount=%d,ZengyaCount=%d,PressureCount=%d\n",
			//	AICount, DICount, AQCount, DQCount, OtherCount, BengzuCount, ZengyaCount, PressureCount)})
			i := 0
			Display0602(fmt.Sprintf("------ AI Parsing %d\n", i))
			for AINum := 1; AINum <= int(AICount); AINum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("AI%02d=%02d 通道数=%d: \n", AINum, dataPart[i], channelCount))
				i += 2
				for j := 1; j <= int(channelCount); j++ {
					v := tools.BytesToFloat32(dataPart[i:i+4], fse.FloatEndian)
					Display0602(fmt.Sprintf("v%02d=%.2f, ", j, v))
					i += 4
					shieldV := dataPart[i]
					Display0602(fmt.Sprintf("屏蔽%02d=%d, ", j, FSToLocalByte(shieldV)))
					i++
					alertV := dataPart[i]
					Display0602(fmt.Sprintf("报警%02d=%d,\n", j, dataPart[i]))
					i++
					addr := GetAddrFromFSE(fse, "AI", AINum, j, "")
					UpdateMemShieldAlert(addr, shieldV, alertV)
					messageList = append(messageList, &QueueValue{
						Addr:       addr,
						Value:      float64(v),
						FSShield:   FSToLocalByte(shieldV),
						FSAlert:    alertV,
						CreateTime: &now,
					})
				}
			}

			Display0602(fmt.Sprintf("------ DI Parsing %d\n", i))
			for DINum := 1; DINum <= int(DICount); DINum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("DI%02d=%02d 通道数=%d:  ", DINum, dataPart[i], channelCount))
				i += 2
				for j := 1; j <= int(channelCount); j++ {
					v := dataPart[i]
					Display0602(fmt.Sprintf("v%02d=%d, ", j, FSToLocalByte(v)))
					messageList = append(messageList, &QueueValue{
						Addr:       GetAddrFromFSE(fse, "DI", DINum, j, ""),
						Value:      float64(FSToLocalByte(v)),
						CreateTime: &now,
					})
					i++
				}
				Display0602("\n")
			}

			Display0602(fmt.Sprintf("------ AQ Parsing %d\n", i))
			for AQNum := 1; AQNum <= int(AQCount); AQNum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("AQ%02d=%02d 通道数=%d: \n", AQNum, dataPart[i], channelCount))
				i += 2
				for j := 1; j <= int(channelCount); j++ {
					v := tools.BytesToFloat32(dataPart[i:i+4], fse.FloatEndian)
					Display0602(fmt.Sprintf("v%02d=%.2f, ", j, v))
					i += 4
					shieldV := dataPart[i]
					Display0602(fmt.Sprintf("屏蔽%02d=%d, ", j, FSToLocalByte(shieldV)))
					i++
					alertV := dataPart[i]
					Display0602(fmt.Sprintf("报警%02d=%d,\n", j, alertV))
					i++
					addr := GetAddrFromFSE(fse, "AQ", AQNum, j, "")
					UpdateMemShieldAlert(addr, shieldV, alertV)
					messageList = append(messageList, &QueueValue{
						Addr:       addr,
						Value:      float64(v),
						FSShield:   FSToLocalByte(shieldV),
						FSAlert:    alertV,
						CreateTime: &now,
					})
				}
			}

			Display0602(fmt.Sprintf("------ DQ Parsing %d\n", i))
			for DQNum := 1; DQNum <= int(DQCount); DQNum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("DQ%02d=%02d 通道数=%d:  ", DQNum, dataPart[i], channelCount))
				i += 2
				for j := 1; j <= int(channelCount); j++ {
					v := dataPart[i]
					Display0602(fmt.Sprintf("v%02d=%d, ", j, FSToLocalByte(v)))
					messageList = append(messageList, &QueueValue{
						Addr:       GetAddrFromFSE(fse, "DQ", DQNum, j, ""),
						Value:      float64(FSToLocalByte(v)),
						CreateTime: &now,
					})
					i++
				}
				Display0602("\n")
			}

			Display0602(fmt.Sprintf("------ Other Parsing %d\n", i))
			for OtherNum := 1; OtherNum <= int(OtherCount); OtherNum++ {
				channelCount := dataPart[i+1]
				Display0602(fmt.Sprintf("Other%02d=%02d 通道数=%d: \n", OtherNum, dataPart[i], channelCount))
				i += 2
				currChannel := 1
				for currChannel <= int(channelCount) {
					channelType := dataPart[i]
					i++
					switch channelType {
					case 0x01: // AI
						v := tools.BytesToFloat32(dataPart[i:i+4], fse.FloatEndian)
						Display0602(fmt.Sprintf("通道类型%02d: v%02d=%.2f,", channelType, currChannel, v))
						i += 4
						shieldV := dataPart[i]
						Display0602(fmt.Sprintf("屏蔽%02d=%d,", currChannel, FSToLocalByte(shieldV)))
						i++
						alertV := dataPart[i]
						Display0602(fmt.Sprintf("报警%02d=%d\n", currChannel, alertV))
						i++
						addr := GetAddrFromFSE(fse, "Other", OtherNum, currChannel, "")
						UpdateMemShieldAlert(addr, shieldV, alertV)
						messageList = append(messageList, &QueueValue{
							Addr:       addr,
							Value:      float64(v),
							FSShield:   FSToLocalByte(shieldV),
							FSAlert:    alertV,
							CreateTime: &now,
						})
					case 0x02: // AQ
						v := tools.BytesToFloat32(dataPart[i:i+4], fse.FloatEndian)
						Display0602(fmt.Sprintf("通道类型%02d: v%02d=%.2f,", channelType, currChannel, v))
						i += 4
						shieldV := dataPart[i]
						Display0602(fmt.Sprintf("屏蔽%02d=%d,", currChannel, FSToLocalByte(shieldV)))
						i++
						alertV := dataPart[i]
						Display0602(fmt.Sprintf("报警%02d=%d\n", currChannel, alertV))
						i++
						addr := GetAddrFromFSE(fse, "Other", OtherNum, currChannel, "")
						UpdateMemShieldAlert(addr, shieldV, alertV)
						messageList = append(messageList, &QueueValue{
							Addr:       addr,
							Value:      float64(v),
							FSShield:   FSToLocalByte(shieldV),
							FSAlert:    alertV,
							CreateTime: &now,
						})
					case 0x03: // DI
						v := dataPart[i]
						Display0602(fmt.Sprintf("通道类型%02d: v%02d=%d\n", channelType, currChannel, FSToLocalByte(v)))
						messageList = append(messageList, &QueueValue{
							Addr:       GetAddrFromFSE(fse, "Other", OtherNum, currChannel, ""),
							Value:      float64(FSToLocalByte(v)),
							CreateTime: &now,
						})
						i++
					case 0x04: // DQ
						v := dataPart[i]
						Display0602(fmt.Sprintf("通道类型%02d: v%02d=%d\n", channelType, currChannel, FSToLocalByte(v)))
						messageList = append(messageList, &QueueValue{
							Addr:       GetAddrFromFSE(fse, "Other", OtherNum, currChannel, ""),
							Value:      float64(FSToLocalByte(v)),
							CreateTime: &now,
						})
						i++
					default:
						err = errors.New(fmt.Sprintf("Other通道类型异常 channelType=%d, i=%d", channelType, i))
						return
					}
					currChannel++
				}
			}

			Display0602(fmt.Sprintf("------ 泵组 Parsing %d\n", i))
			for num := 1; num <= int(BengzuCount); num++ {
				Display0602(fmt.Sprintf("[%d] 泵组序号%02d: ", num, dataPart[i]))
				i++
				Display0602(fmt.Sprintf("开控制%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "开控制"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602(fmt.Sprintf("关控制%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "关控制"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602(fmt.Sprintf("开状态%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "开状态"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602(fmt.Sprintf("关状态%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "关状态"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602(fmt.Sprintf("连锁%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "泵组电磁阀", num, 0, "连锁"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602("\n")
			}

			Display0602(fmt.Sprintf("------ 增压 Parsing %d\n", i))
			for num := 1; num <= int(ZengyaCount); num++ {
				Display0602(fmt.Sprintf("[%d] 增压泵序号%02d: ", num, FSToLocalByte(dataPart[i])))
				i++
				Display0602(fmt.Sprintf("连锁%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "增压泵电磁阀", num, 0, "连锁"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602("\n")
			}

			Display0602(fmt.Sprintf("------ 压力 Parsing %d\n", i))
			for num := 1; num <= int(PressureCount); num++ {
				Display0602(fmt.Sprintf("[%d] 压力电磁阀序号%02d: ", num, dataPart[i]))
				i++
				Display0602(fmt.Sprintf("连锁%d,", FSToLocalByte(dataPart[i])))
				messageList = append(messageList, &QueueValue{
					Addr:       GetAddrFromFSE(fse, "压力电磁阀", num, 0, "连锁"),
					Value:      float64(FSToLocalByte(dataPart[i])),
					CreateTime: &now,
				})
				i++
				Display0602("\n")
			}
			go VariablesMap.PushMessageToClients(messageList)
			cmd := fmt.Sprintf("%02d%02d", funcCode, cmdCode)
			if cmd != "0602" {
				ResponseDo(fse, cmd, "success")
			}
		} else {
			j_log.LogError([]interface{}{fmt.Sprintf("异常,帧序号大于帧总数 %d > %d", frameNum, frameCount)})
			err = errors.New(fmt.Sprintf("异常,帧序号大于帧总数 %d > %d", frameNum, frameCount))
			return
		}
	}
	return
}

/*TCPClientRequest ------*/

type FSTCPRequest struct {
	ReqTime  int64
	RespTime int64
	Resp0101 chan string
	Resp0181 chan string
	Resp0102 chan string
	Resp0182 chan string
	Resp0202 chan string
	Resp0282 chan string
	Resp0203 chan string
	Resp0283 chan string
	Resp0204 chan string
	Resp0284 chan string
	Resp0205 chan string
	Resp0285 chan string
	Resp0206 chan string
	Resp0286 chan string
	Resp0301 chan string
	Resp0381 chan string
	Resp0302 chan string
	Resp0382 chan string
	Resp0303 chan string
	Resp0383 chan string
	Resp0304 chan string
	Resp0384 chan string
	Resp0305 chan string
	Resp0385 chan string
	Resp0306 chan string
	Resp0386 chan string
	Resp0307 chan string
	Resp0387 chan string
	Resp0308 chan string
	Resp0388 chan string
	Resp0401 chan string
	Resp0481 chan string

	Resp0402 chan string
	Resp0482 chan string
	Resp0403 chan string
	Resp0483 chan string
	Resp0404 chan string
	Resp0484 chan string
	Resp0405 chan string
	Resp0485 chan string
	Resp0406 chan string
	Resp0486 chan string

	Resp0501 chan string
	Resp0581 chan string
	Resp0502 chan string
	Resp0582 chan string
	Resp0503 chan string
	Resp0583 chan string
	Resp0504 chan string
	Resp0584 chan string
	Resp0505 chan string
	Resp0585 chan string
	Resp0506 chan string
	Resp0586 chan string
	Resp0507 chan string
	Resp0587 chan string
	Resp0508 chan string
	Resp0588 chan string
	Resp0509 chan string
	Resp0589 chan string

	Resp0601 chan string
	Resp0681 chan string
	Resp0602 chan string
	Resp0612 chan string
	Resp0682 chan string
	Resp0603 chan string
	Resp0683 chan string
	Resp0604 chan string
	Resp0684 chan string
	Resp0605 chan string
	Resp0685 chan string
}

type FSTCPRequestMapStu struct {
	M map[int64]*FSTCPRequest
	sync.RWMutex
}

func NewFSTCPRequestMap() *FSTCPRequestMapStu {
	return &FSTCPRequestMapStu{
		M: make(map[int64]*FSTCPRequest),
	}
}
func NewFrameCacheMap() *FrameCacheMapStu {
	return &FrameCacheMapStu{
		M: make(map[string]*FrameCache),
	}
}

func NewFSTCPRequest() *FSTCPRequest {
	return &FSTCPRequest{
		ReqTime:  time.Now().Unix(),
		Resp0101: make(chan string, 10),
		Resp0102: make(chan string, 10),
		Resp0181: make(chan string, 10),
		Resp0182: make(chan string, 10),
		Resp0202: make(chan string, 10),
		Resp0282: make(chan string, 10),
		Resp0203: make(chan string, 10),
		Resp0283: make(chan string, 10),
		Resp0204: make(chan string, 10),
		Resp0284: make(chan string, 10),
		Resp0205: make(chan string, 10),
		Resp0285: make(chan string, 10),
		Resp0206: make(chan string, 10),
		Resp0286: make(chan string, 10),
		Resp0301: make(chan string, 10),
		Resp0381: make(chan string, 10),
		Resp0302: make(chan string, 10),
		Resp0382: make(chan string, 10),
		Resp0303: make(chan string, 10),
		Resp0383: make(chan string, 10),
		Resp0304: make(chan string, 10),
		Resp0384: make(chan string, 10),
		Resp0305: make(chan string, 10),
		Resp0385: make(chan string, 10),
		Resp0306: make(chan string, 10),
		Resp0386: make(chan string, 10),
		Resp0307: make(chan string, 10),
		Resp0387: make(chan string, 10),
		Resp0308: make(chan string, 10),
		Resp0388: make(chan string, 10),
		Resp0401: make(chan string, 10),
		Resp0481: make(chan string, 10),

		Resp0402: make(chan string, 10),
		Resp0482: make(chan string, 10),
		Resp0403: make(chan string, 10),
		Resp0483: make(chan string, 10),
		Resp0404: make(chan string, 10),
		Resp0484: make(chan string, 10),
		Resp0405: make(chan string, 10),
		Resp0485: make(chan string, 10),
		Resp0406: make(chan string, 10),
		Resp0486: make(chan string, 10),

		Resp0501: make(chan string, 10),
		Resp0581: make(chan string, 10),
		Resp0502: make(chan string, 10),
		Resp0582: make(chan string, 10),
		Resp0503: make(chan string, 10),
		Resp0583: make(chan string, 10),
		Resp0504: make(chan string, 10),
		Resp0584: make(chan string, 10),
		Resp0505: make(chan string, 10),
		Resp0585: make(chan string, 10),
		Resp0506: make(chan string, 10),
		Resp0586: make(chan string, 10),
		Resp0507: make(chan string, 10),
		Resp0587: make(chan string, 10),
		Resp0508: make(chan string, 10),
		Resp0588: make(chan string, 10),
		Resp0509: make(chan string, 10),
		Resp0589: make(chan string, 10),

		Resp0601: make(chan string, 10),
		Resp0681: make(chan string, 10),
		Resp0602: make(chan string, 10),
		Resp0612: make(chan string, 10),
		Resp0682: make(chan string, 10),
		Resp0603: make(chan string, 10),
		Resp0683: make(chan string, 10),
		Resp0604: make(chan string, 10),
		Resp0684: make(chan string, 10),
		Resp0605: make(chan string, 10),
		Resp0685: make(chan string, 10),
	}
}

func ResponseDo(fse *FSEquip, fc string, data string) {
	fse.TcpClient.Requests.RLock()
	defer fse.TcpClient.Requests.RUnlock()
	//j_log.LogInfo([]interface{}{"当前client request 数量:", len(fse.TcpClient.Requests.M)})
	for _, req := range fse.TcpClient.Requests.M {
		if time.Now().Unix()-req.ReqTime > 5 {
			continue
		}
		switch fc {
		case "0101":
			req.Resp0101 <- data
		case "0181":
			req.Resp0181 <- data
		case "0102":
			req.Resp0102 <- data
		case "0182":
			req.Resp0182 <- data
		case "0202":
			req.Resp0202 <- data
		case "0282":
			req.Resp0282 <- data
		case "0203":
			req.Resp0203 <- data
		case "0283":
			req.Resp0283 <- data
		case "0204":
			req.Resp0204 <- data
		case "0284":
			req.Resp0284 <- data
		case "0205":
			req.Resp0205 <- data
		case "0285":
			req.Resp0285 <- data
		case "0206":
			req.Resp0206 <- data
		case "0286":
			req.Resp0286 <- data

		case "0301":
			req.Resp0301 <- data
		case "0381":
			req.Resp0381 <- data
		case "0302":
			req.Resp0302 <- data
		case "0382":
			req.Resp0382 <- data
		case "0303":
			req.Resp0303 <- data
		case "0383":
			req.Resp0383 <- data
		case "0304":
			req.Resp0304 <- data
		case "0384":
			req.Resp0384 <- data
		case "0305":
			req.Resp0305 <- data
		case "0385":
			req.Resp0385 <- data
		case "0306":
			req.Resp0306 <- data
		case "0386":
			req.Resp0386 <- data
		case "0307":
			req.Resp0307 <- data
		case "0387":
			req.Resp0387 <- data
		case "0308":
			req.Resp0308 <- data
		case "0388":
			req.Resp0388 <- data
		case "0401":
			req.Resp0401 <- data
		case "0481":
			req.Resp0481 <- data
		case "0402":
			req.Resp0402 <- data
		case "0482":
			req.Resp0482 <- data
		case "0403":
			req.Resp0403 <- data
		case "0483":
			req.Resp0483 <- data
		case "0404":
			req.Resp0404 <- data
		case "0484":
			req.Resp0484 <- data
		case "0405":
			req.Resp0405 <- data
		case "0485":
			req.Resp0485 <- data
		case "0406":
			req.Resp0406 <- data
		case "0486":
			req.Resp0486 <- data

		case "0501":
			req.Resp0501 <- data
		case "0581":
			req.Resp0581 <- data
		case "0502":
			req.Resp0502 <- data
		case "0582":
			req.Resp0582 <- data
		case "0503":
			req.Resp0503 <- data
		case "0583":
			req.Resp0583 <- data
		case "0504":
			req.Resp0505 <- data
		case "0584":
			req.Resp0584 <- data
		case "0505":
			req.Resp0505 <- data
		case "0585":
			req.Resp0585 <- data
		case "0506":
			req.Resp0506 <- data
		case "0586":
			req.Resp0586 <- data
		case "0507":
			req.Resp0507 <- data
		case "0587":
			req.Resp0587 <- data
		case "0508":
			req.Resp0508 <- data
		case "0588":
			req.Resp0588 <- data
		case "0509":
			req.Resp0509 <- data
		case "0589":
			req.Resp0589 <- data

		case "0601":
			req.Resp0601 <- data
		case "0681":
			req.Resp0681 <- data
		case "0602":
			req.Resp0602 <- data
		case "0612":
			req.Resp0612 <- data
		case "0682":
			req.Resp0682 <- data
		case "0603":
			req.Resp0603 <- data
		case "0683":
			req.Resp0683 <- data
		case "0604":
			req.Resp0604 <- data
		case "0684":
			req.Resp0684 <- data
		case "0605":
			req.Resp0605 <- data
		case "0685":
			req.Resp0685 <- data
		}

	}
}
func (r *FSTCPRequestMapStu) Set(key int64, v *FSTCPRequest) {
	r.Lock()
	defer r.Unlock()
	r.M[key] = v
}

func (r *FSTCPRequestMapStu) Get(key int64) (v *FSTCPRequest, ok bool) {
	r.RLock()
	defer r.RUnlock()
	v, ok = r.M[key]
	return
}

func (r *FSTCPRequestMapStu) Delete(key int64) {
	r.Lock()
	defer r.Unlock()
	delete(r.M, key)
}

func Ip2Bytes(ip string) (b []byte) {
	b = make([]byte, 4)
	ipArr := strings.Split(ip, ".")
	if len(ipArr) != 4 {
		return
	}
	for i := 0; i < 4; i++ {
		n, _ := strconv.Atoi(ipArr[i])
		b[i] = byte(n)
	}
	return
}

func Addr2Bytes(addr string) (b []byte) {
	b = make([]byte, 2)
	b[0] = 0
	b[1] = 0
	arr := strings.Split(addr, "-")
	if len(arr) != 4 {
		return
	}
	code3, _ := strconv.Atoi(arr[2])
	code4, _ := strconv.Atoi(arr[3])
	b[0] = byte(code3)
	b[1] = byte(code4)
	return
}

func FixDataLength(fse *FSEquip, data []byte) {
	length := len(data)
	lengthBytes := tools.Uint16ToBytes(uint16(length), fse.IntEndian)
	data[3] = lengthBytes[0]
	data[4] = lengthBytes[1]
}

func GenFSFrameData0101() (data []byte) {
	data = []byte{0x5A, 0x01, 0x01, 0x00, 0x0C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA5}
	return
}

// GenFSFrameData0102 ip设置数据
func GenFSFrameData0102(fse *FSEquip, ip1, ip2 string, port1, port2 uint16, param1, param2, param3 float64, redundantEnable uint8) (data []byte, err error) {
	if !tools.IsValidIP(ip1) || !tools.IsValidIP(ip2) {
		err = errors.New("ip地址不合法")
		return
	}
	ip1Bytes := Ip2Bytes(ip1)
	port1Bytes := tools.Uint16ToBytes(port1, fse.IntEndian)

	ip2Bytes := Ip2Bytes(ip2)
	port2Bytes := tools.Uint16ToBytes(port2, fse.IntEndian)

	param1Bytes := tools.Float32ToBytes(float32(param1), fse.FloatEndian)
	param2Bytes := tools.Float32ToBytes(float32(param2), fse.FloatEndian)
	param3Bytes := tools.Float32ToBytes(float32(param3), fse.FloatEndian)

	data = []byte{0x5A, 0x01, 0x02, 0x00, 0x24, 0x01, 0x01}

	data = append(data, NormalBoolToFSBool(redundantEnable))

	data = append(data, ip1Bytes...)       // IP1
	data = append(data, port1Bytes[0:]...) // PORT1
	data = append(data, ip2Bytes...)       // IP2
	data = append(data, port2Bytes[0:]...) // PORT2

	data = append(data, param1Bytes...)               // 参数1 float32
	data = append(data, param2Bytes...)               // 参数1 float32
	data = append(data, param3Bytes...)               // 参数1 float32
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾

	FixDataLength(fse, data)
	return
}

func GetLimitRealValue(baseVar *FrameItem, t string) (f float64) {
	switch t {
	case "upper2":
		if baseVar.Upper2LimitVarAddr == "" {
			//j_log.LogDebug([]interface{}{fmt.Sprintf("%s = %v\n", baseVar.Addr, ".Upper2LimitVarAddr为空")})
			return baseVar.Upper2LimitValue
		}
		v, ok := VariablesMap.Get(baseVar.Upper2LimitVarAddr)
		if !ok {
			//j_log.LogDebug([]interface{}{fmt.Sprintf("%s, %v\n", baseVar.Upper2LimitVarAddr, "未找到变量地址")})
			return 0
		}
		//j_log.LogDebug([]interface{}{fmt.Sprintf("%s = %v\n", baseVar.Upper2LimitVarAddr, v.Value)})
		return v.Value
	case "upper":
		if baseVar.UpperLimitVarAddr == "" {
			return baseVar.UpperLimitValue
		}
		v, ok := VariablesMap.Get(baseVar.UpperLimitVarAddr)
		if !ok {
			return 0
		}
		//fmt.Printf("--- %s = %v\n", baseVar.UpperLimitVarAddr, v.Value)
		return v.Value
	case "lower":
		if baseVar.LowerLimitVarAddr == "" {
			return baseVar.LowerLimitValue
		}
		v, ok := VariablesMap.Get(baseVar.LowerLimitVarAddr)
		if !ok {
			return 0
		}
		//fmt.Printf("--- %s = %v\n", baseVar.LowerLimitVarAddr, v.Value)
		return v.Value
	case "lower2":
		if baseVar.Lower2LimitVarAddr == "" {
			return baseVar.Lower2LimitValue
		}
		v, ok := VariablesMap.Get(baseVar.Lower2LimitVarAddr)
		if !ok {
			return 0
		}
		//fmt.Printf("--- %s = %v\n", baseVar.Lower2LimitVarAddr, v.Value)
		return v.Value
	}
	return
}
func GetShieldAlertValue(baseVar *FrameItem, t string) uint8 {
	switch t {
	case "shield":
		if baseVar.ShieldVarAddr == "" {
			return baseVar.Shield
		}
		v, ok := VariablesMap.Get(baseVar.ShieldVarAddr)
		if !ok {
			return 0
		}
		//fmt.Printf("--- %s = %v\n", baseVar.Lower2LimitVarAddr, v.Value)
		return uint8(v.Value)
	case "alert":
		if baseVar.AlertVarAddr == "" {
			return baseVar.AlertBit
		}
		v, ok := VariablesMap.Get(baseVar.AlertVarAddr)
		if !ok {
			return 0
		}
		//fmt.Printf("--- %s = %v\n", baseVar.Lower2LimitVarAddr, v.Value)
		return uint8(v.Value)
	}
	return 0
}

// GenFSModuleData0202 AI模块下发数据
func GenFSModuleData0202(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x02, 0x02, 0x00, 0x24, 0x01, 0x01}
	AICode, _ := strconv.Atoi(code3) // AI序号
	ChannelNum := 0                  // 通道数
	contentBytes := make([]byte, 0)  // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "AI" {
			if row.Code3 == code3 {
				for _, item := range row.FrameItem {
					if len(item.Addr) > 12 {
						continue
					}
					ChannelNum++
					upperLimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "upper")), fse.FloatEndian)
					lowerLimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "lower")), fse.FloatEndian)
					upper2LimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "upper2")), fse.FloatEndian)
					lower2LimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "lower2")), fse.FloatEndian)
					rangeUpperLimit := tools.Float32ToBytes(float32(item.RangeUpperLimit), fse.FloatEndian)
					rangeLowerLimit := tools.Float32ToBytes(float32(item.RangeLowerLimit), fse.FloatEndian)
					contentBytes = append(contentBytes, upperLimitValue...)
					contentBytes = append(contentBytes, lowerLimitValue...)
					contentBytes = append(contentBytes, upper2LimitValue...)
					contentBytes = append(contentBytes, lower2LimitValue...)
					contentBytes = append(contentBytes, rangeUpperLimit...)
					contentBytes = append(contentBytes, rangeLowerLimit...)
					contentBytes = append(contentBytes, NormalBoolToFSBool(GetShieldAlertValue(item, "shield")))
					contentBytes = append(contentBytes, NormalBoolToFSBool(GetShieldAlertValue(item, "alert")))
					contentBytes = append(contentBytes, item.Formula)
					contentBytes = append(contentBytes, item.DiagMode)
				}
				break
			}
		}
	}
	if ChannelNum == 0 {
		err = errors.New("当前模块不存在或通道数为0")
		return
	}
	data = append(data, fse.DS.AI, byte(AICode), byte(ChannelNum))
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}

// GenFSModuleData0203 AQ模块下发数据
func GenFSModuleData0203(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x02, 0x03, 0x00, 0x00, 0x01, 0x01}
	AINum := 0                       // AI总数
	AICode, _ := strconv.Atoi(code3) // AI序号
	ChannelNum := 0                  // 通道数
	contentBytes := make([]byte, 0)  // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "AQ" {
			AINum++
			if row.Code3 == code3 {
				for _, item := range row.FrameItem {
					if item.IsInternal == 1 {
						continue
					}
					ChannelNum++
					upperLimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "upper")), fse.FloatEndian)
					lowerLimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "lower")), fse.FloatEndian)
					upper2LimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "upper2")), fse.FloatEndian)
					lower2LimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "lower2")), fse.FloatEndian)
					rangeUpperLimit := tools.Float32ToBytes(float32(item.RangeUpperLimit), fse.FloatEndian)
					rangeLowerLimit := tools.Float32ToBytes(float32(item.RangeLowerLimit), fse.FloatEndian)
					contentBytes = append(contentBytes, upperLimitValue...)
					contentBytes = append(contentBytes, lowerLimitValue...)
					contentBytes = append(contentBytes, upper2LimitValue...)
					contentBytes = append(contentBytes, lower2LimitValue...)
					contentBytes = append(contentBytes, rangeUpperLimit...)
					contentBytes = append(contentBytes, rangeLowerLimit...)
					contentBytes = append(contentBytes, NormalBoolToFSBool(item.Shield))
					contentBytes = append(contentBytes, NormalBoolToFSBool(item.AlertBit))
					contentBytes = append(contentBytes, item.Formula)
					contentBytes = append(contentBytes, item.DiagMode)
				}
			}
		}
	}
	if ChannelNum == 0 {
		err = errors.New("当前模块不存在或通道数为0")
		return
	}
	data = append(data, byte(AINum), byte(AICode), byte(ChannelNum))
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}

// GenFSModuleData0204 DI模块下发数据
func GenFSModuleData0204(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x02, 0x04, 0x00, 0x00, 0x01, 0x01}
	AINum := 0                       // AI总数
	AICode, _ := strconv.Atoi(code3) // AI序号
	ChannelNum := 0                  // 通道数
	contentBytes := make([]byte, 0)  // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "DI" {
			AINum++
			if row.Code3 == code3 {
				for _, item := range row.FrameItem {
					if item.IsInternal == 1 {
						continue
					}
					ChannelNum++
					shieldTime := tools.Uint16ToBytes(uint16(item.ShieldTime), fse.IntEndian)
					contentBytes = append(contentBytes, NormalBoolToFSBool(item.Shield))
					contentBytes = append(contentBytes, shieldTime[:]...)
				}
			}
		}
	}
	if ChannelNum == 0 {
		err = errors.New("当前模块不存在或通道数为0")
		return
	}
	data = append(data, byte(AINum), byte(AICode), byte(ChannelNum))
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}

// GenFSModuleData0205 DQ模块下发数据
func GenFSModuleData0205(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x02, 0x05, 0x00, 0x00, 0x01, 0x01}
	AINum := 0                       // AI总数
	AICode, _ := strconv.Atoi(code3) // AI序号
	ChannelNum := 0                  // 通道数
	contentBytes := make([]byte, 0)  // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "DQ" {
			AINum++
			if row.Code3 == code3 {
				for _, item := range row.FrameItem {
					if item.IsInternal == 1 {
						continue
					}
					ChannelNum++
					shieldTime := tools.Uint16ToBytes(uint16(item.ShieldTime), fse.IntEndian)
					contentBytes = append(contentBytes, NormalBoolToFSBool(item.Shield))
					contentBytes = append(contentBytes, shieldTime[:]...)
				}
			}
		}
	}
	if ChannelNum == 0 {
		err = errors.New("当前模块不存在或通道数为0")
		return
	}
	data = append(data, byte(AINum), byte(AICode), byte(ChannelNum))
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}

// GenFSModuleData0206 Other模块下发数据, 通道类型 0x01,0x02,0x03,0x04, 见 FS自研设备协议excel
func GenFSModuleData0206(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x02, 0x06, 0x00, 0x24, 0x01, 0x01}
	AINum := 0                       // 总数
	AICode, _ := strconv.Atoi(code3) // 序号
	ChannelNum := 0                  // 通道数
	contentBytes := make([]byte, 0)  // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "Other" {
			AINum++
			if row.Code3 == code3 {
				for _, item := range row.FrameItem {
					if item.IsInternal == 1 {
						continue
					}
					ChannelNum++
					switch item.ChannelType {
					case "AI":
						contentBytes = append(contentBytes, 0x01)
						upperLimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "upper")), fse.FloatEndian)
						lowerLimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "lower")), fse.FloatEndian)
						upper2LimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "upper2")), fse.FloatEndian)
						lower2LimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "lower2")), fse.FloatEndian)
						rangeUpperLimit := tools.Float32ToBytes(float32(item.RangeUpperLimit), fse.FloatEndian)
						rangeLowerLimit := tools.Float32ToBytes(float32(item.RangeLowerLimit), fse.FloatEndian)
						contentBytes = append(contentBytes, upperLimitValue...)
						contentBytes = append(contentBytes, lowerLimitValue...)
						contentBytes = append(contentBytes, upper2LimitValue...)
						contentBytes = append(contentBytes, lower2LimitValue...)
						contentBytes = append(contentBytes, rangeUpperLimit...)
						contentBytes = append(contentBytes, rangeLowerLimit...)
						contentBytes = append(contentBytes, NormalBoolToFSBool(item.Shield))
						contentBytes = append(contentBytes, NormalBoolToFSBool(item.AlertBit))
						contentBytes = append(contentBytes, item.Formula)
						contentBytes = append(contentBytes, item.DiagMode)
					case "AQ":
						contentBytes = append(contentBytes, 0x02)

						upperLimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "upper")), fse.FloatEndian)
						lowerLimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "lower")), fse.FloatEndian)
						upper2LimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "upper2")), fse.FloatEndian)
						lower2LimitValue := tools.Float32ToBytes(float32(GetLimitRealValue(item, "lower2")), fse.FloatEndian)
						rangeUpperLimit := tools.Float32ToBytes(float32(item.RangeUpperLimit), fse.FloatEndian)
						rangeLowerLimit := tools.Float32ToBytes(float32(item.RangeLowerLimit), fse.FloatEndian)
						contentBytes = append(contentBytes, upperLimitValue...)
						contentBytes = append(contentBytes, lowerLimitValue...)
						contentBytes = append(contentBytes, upper2LimitValue...)
						contentBytes = append(contentBytes, lower2LimitValue...)
						contentBytes = append(contentBytes, rangeUpperLimit...)
						contentBytes = append(contentBytes, rangeLowerLimit...)
						contentBytes = append(contentBytes, NormalBoolToFSBool(item.Shield))
						contentBytes = append(contentBytes, NormalBoolToFSBool(item.AlertBit))
						contentBytes = append(contentBytes, item.Formula)
						contentBytes = append(contentBytes, item.DiagMode)
					case "DI":
						contentBytes = append(contentBytes, 0x03)

						shieldTime := tools.Uint16ToBytes(uint16(item.ShieldTime), fse.IntEndian)
						contentBytes = append(contentBytes, NormalBoolToFSBool(item.Shield))
						contentBytes = append(contentBytes, shieldTime[:]...)
					case "DQ":
						contentBytes = append(contentBytes, 0x04)

						shieldTime := tools.Uint16ToBytes(uint16(item.ShieldTime), fse.IntEndian)
						contentBytes = append(contentBytes, NormalBoolToFSBool(item.Shield))
						contentBytes = append(contentBytes, shieldTime[:]...)
					}
				}
			}
		}
	}
	if ChannelNum == 0 {
		err = errors.New("当前模块不存在或通道数为0")
		return
	}
	data = append(data, byte(AINum), byte(AICode), byte(ChannelNum))
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}

func GenFSModuleData0301(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x03, 0x01, 0xFF, 0xFF}
	ModelNum := 0                       // 模型总数
	ModelCode, _ := strconv.Atoi(code3) // 模型序号
	for _, row := range fse.FSModule {
		if row.ModuleType == "泵组电磁阀" {
			ModelNum++
		}
	}
	data = append(data, byte(ModelNum), byte(ModelCode), 0x01) // 模型总数和序号, 内部变量
	found := false
	for _, row := range fse.FSModule {
		if row.ModuleType == "泵组电磁阀" && row.Code3 == code3 {
			contentModel := BengzuModel{}
			err = json.Unmarshal([]byte(row.JsonDetail), &contentModel)
			if err != nil {
				return
			}
			/*--- 泵组控制 ---*/
			data = append(data, NormalBoolToFSBool(contentModel.BengzuStartControlValue))
			data = append(data, NormalBoolToFSBool(contentModel.BengzuStopControlValue))
			data = append(data, NormalBoolToFSBool(contentModel.BengzuStartStateValue))
			data = append(data, NormalBoolToFSBool(contentModel.BengzuStopStateValue))
			data = append(data, NormalBoolToFSBool(contentModel.LiansuoValue))
			data = append(data, contentModel.ControlMethodValue)
			data = append(data, tools.Float32ToBytes(float32(contentModel.BengzuParam1Value), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.BengzuParam2Value), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.BengzuParam3Value), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.BengzuParam4Value), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.BengzuParam5Value), fse.FloatEndian)...)

			data = append(data, 0x02) // 外部变量

			data = append(data, Addr2Bytes(contentModel.BengqianPressure)...)
			data = append(data, Addr2Bytes(contentModel.BengqianStartControl)...)
			data = append(data, Addr2Bytes(contentModel.BengqianStopControl)...)
			data = append(data, Addr2Bytes(contentModel.BengqianStartState)...)
			data = append(data, Addr2Bytes(contentModel.BengqianStopState)...)

			data = append(data, Addr2Bytes(contentModel.QianjibengStartControl)...)
			data = append(data, Addr2Bytes(contentModel.QianjibengStopControl)...)
			data = append(data, Addr2Bytes(contentModel.QianjibengStartState)...)
			data = append(data, Addr2Bytes(contentModel.QianjibengStopState)...)

			data = append(data, Addr2Bytes(contentModel.LuocibengStartControl)...)
			data = append(data, Addr2Bytes(contentModel.LuocibengStopControl)...)
			data = append(data, Addr2Bytes(contentModel.LuocibengStartState)...)
			data = append(data, Addr2Bytes(contentModel.LuocibengStopState)...)

			data = append(data, Addr2Bytes(contentModel.RemoteLocal)...)
			found = true
			break
		}
	}
	if !found {
		err = errors.New("未找到当前模型数据")
		return
	}
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}
func GenFSModuleData0302(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x03, 0x02, 0x00, 0x24}
	ModelNum := 0                       // 模型总数
	ModelCode, _ := strconv.Atoi(code3) // 模型序号
	contentBytes := make([]byte, 0)     // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "增压泵电磁阀" {
			ModelNum++
		}
	}
	data = append(data, byte(ModelNum), byte(ModelCode)) // 模型总数和序号
	data = append(data, 0x01)                            // 内部变量
	found := false
	for _, row := range fse.FSModule {
		if row.ModuleType == "增压泵电磁阀" && row.Code3 == code3 {
			contentModel := ZengyaModel{}
			err = json.Unmarshal([]byte(row.JsonDetail), &contentModel)
			if err != nil {
				return
			}
			data = append(data, NormalBoolToFSBool(contentModel.LiansuoValue))
			data = append(data, contentModel.ControlMethodValue)

			data = append(data, 0x02) // 外部模块量
			data = append(data, Addr2Bytes(contentModel.BengqianPressure)...)
			data = append(data, Addr2Bytes(contentModel.BengqianStartControl)...)
			data = append(data, Addr2Bytes(contentModel.BengqianStopControl)...)
			data = append(data, Addr2Bytes(contentModel.BengqianStartState)...)
			data = append(data, Addr2Bytes(contentModel.BengqianStopState)...)

			data = append(data, Addr2Bytes(contentModel.ZengyaStartControl)...)
			data = append(data, Addr2Bytes(contentModel.ZengyaStopControl)...)
			data = append(data, Addr2Bytes(contentModel.ZengyaStartState)...)
			data = append(data, Addr2Bytes(contentModel.ZengyaStopState)...)
			data = append(data, Addr2Bytes(contentModel.RemoteLocal)...)
			found = true
			break
		}
	}
	if !found {
		err = errors.New("未找到当前模型数据")
		return
	}
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}
func GenFSModuleData0303(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x03, 0x03, 0x00, 0x24}
	ModelNum := 0                       // 模型总数
	ModelCode, _ := strconv.Atoi(code3) // 模型序号
	contentBytes := make([]byte, 0)     // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "电调阀" {
			ModelNum++
		}
	}
	data = append(data, byte(ModelNum), byte(ModelCode)) // 模型总数和序号
	data = append(data, 0x02)                            // 外部模块量
	found := false
	for _, row := range fse.FSModule {
		if row.ModuleType == "电调阀" && row.Code3 == code3 {
			contentModel := DiantiaoSVModel{}
			err = json.Unmarshal([]byte(row.JsonDetail), &contentModel)
			if err != nil {
				return
			}
			data = append(data, Addr2Bytes(contentModel.CurrentKaidu)...)
			data = append(data, Addr2Bytes(contentModel.SetKaidu)...)
			data = append(data, Addr2Bytes(contentModel.Control)...)
			data = append(data, Addr2Bytes(contentModel.SetStep)...)
			data = append(data, Addr2Bytes(contentModel.SelfInspection)...)

			data = append(data, Addr2Bytes(contentModel.Up)...)
			data = append(data, Addr2Bytes(contentModel.Down)...)
			data = append(data, Addr2Bytes(contentModel.AllOn)...)
			data = append(data, Addr2Bytes(contentModel.AllOff)...)
			data = append(data, Addr2Bytes(contentModel.AllOnState)...)
			data = append(data, Addr2Bytes(contentModel.AllOffState)...)
			data = append(data, Addr2Bytes(contentModel.QianjiPressure)...)
			data = append(data, Addr2Bytes(contentModel.HoujiPressure)...)
			data = append(data, Addr2Bytes(contentModel.DestPressure)...)

			data = append(data, Addr2Bytes(contentModel.P)...)
			data = append(data, Addr2Bytes(contentModel.I)...)
			data = append(data, Addr2Bytes(contentModel.D)...)

			data = append(data, Addr2Bytes(contentModel.CustomStartControl)...)
			data = append(data, Addr2Bytes(contentModel.CustomStopControl)...)
			data = append(data, Addr2Bytes(contentModel.CustomStartState)...)
			data = append(data, Addr2Bytes(contentModel.CustomStopState)...)
			data = append(data, Addr2Bytes(contentModel.PID)...)
			data = append(data, Addr2Bytes(contentModel.RemoteLocal)...)
			data = append(data, Addr2Bytes(contentModel.ControlMethod)...)
			found = true
			break
		}
	}
	if !found {
		err = errors.New("未找到当前模型数据")
		return
	}
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}

func GenFSModuleData0304(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x03, 0x04, 0x00, 0x24}
	ModelNum := 0                       // 模型总数
	ModelCode, _ := strconv.Atoi(code3) // 模型序号
	contentBytes := make([]byte, 0)     // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "压力电磁阀" {
			ModelNum++
		}
	}
	data = append(data, byte(ModelNum), byte(ModelCode)) // 模型总数和序号
	data = append(data, 0x01)                            // 内部变量
	found := false
	for _, row := range fse.FSModule {
		if row.ModuleType == "压力电磁阀" && row.Code3 == code3 {
			contentModel := PressureSVModel{}
			err = json.Unmarshal([]byte(row.JsonDetail), &contentModel)
			if err != nil {
				return
			}
			data = append(data, NormalBoolToFSBool(contentModel.LiansuoValue))
			data = append(data, contentModel.ControlMethodValue)

			data = append(data, 0x02) // 外部模块量
			data = append(data, Addr2Bytes(contentModel.Pressure)...)
			data = append(data, Addr2Bytes(contentModel.SVStartControl)...)
			data = append(data, Addr2Bytes(contentModel.SVStopControl)...)
			data = append(data, Addr2Bytes(contentModel.SVStartState)...)
			data = append(data, Addr2Bytes(contentModel.SVStopState)...)

			found = true
			break
		}
	}
	if !found {
		err = errors.New("未找到当前模型数据")
		return
	}
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}
func GenFSModuleData0305(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x03, 0x05, 0xFF, 0xFF}
	ModelNum := 0                       // 模型总数
	ModelCode, _ := strconv.Atoi(code3) // 模型序号
	contentBytes := make([]byte, 0)     // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "电源控制" {
			ModelNum++
		}
	}
	data = append(data, byte(ModelNum), byte(ModelCode)) // 模型总数和序号
	data = append(data, 0x03)                            // 变量类型
	found := false
	var addrArr [3]byte
	for _, row := range fse.FSModule {
		if row.ModuleType == "电源控制" && row.Code3 == code3 {
			contentModel := PowerModel{}
			err = json.Unmarshal([]byte(row.JsonDetail), &contentModel)
			if err != nil {
				return
			}
			//fmt.Printf("debug 电源控制 %s\n", row.JsonDetail)
			if !tools.IsValidIP(contentModel.IP) {
				err = errors.New("IP地址格式错误")
				return
			}
			data = append(data, contentModel.PLCType) // PLC类型
			ipArr := strings.Split(contentModel.IP, ".")
			ip1, _ := strconv.Atoi(ipArr[0])
			ip2, _ := strconv.Atoi(ipArr[1])
			ip3, _ := strconv.Atoi(ipArr[2])
			ip4, _ := strconv.Atoi(ipArr[3])
			portBytes := tools.Uint16ToBytes(contentModel.Port, fse.IntEndian)
			data = append(data, byte(ip1), byte(ip2), byte(ip3), byte(ip4), portBytes[0], portBytes[1]) // IP地址和端口
			data = append(data, contentModel.U1Type)                                                    // real 类型
			b := tools.Uint16ToBytes(contentModel.U1BlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.U1AddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.U2Type) // real 类型
			b = tools.Uint16ToBytes(contentModel.U2BlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.U2AddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.U3Type) // real 类型
			b = tools.Uint16ToBytes(contentModel.U3BlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.U3AddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.I1Type) // real 类型
			b = tools.Uint16ToBytes(contentModel.I1BlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.I1AddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.I2Type) // real 类型
			b = tools.Uint16ToBytes(contentModel.I2BlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.I2AddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.I3Type) // real 类型
			b = tools.Uint16ToBytes(contentModel.I3BlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.I3AddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.FType) // real 类型
			b = tools.Uint16ToBytes(contentModel.FBlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.FAddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.ActivePowerType) // real 类型
			b = tools.Uint16ToBytes(contentModel.ActivePowerBlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.ActivePowerAddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.ReactivePowerType) // real 类型
			b = tools.Uint16ToBytes(contentModel.ReactivePowerBlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.ReactivePowerAddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.ApparentPowerType) // real 类型
			b = tools.Uint16ToBytes(contentModel.ApparentPowerBlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.ApparentPowerAddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			found = true
			break
		}
	}
	if !found {
		err = errors.New("未找到当前模型数据")
		return
	}
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	//fmt.Printf("DEBUG GenFSModuleData0306: %s", tools.ByteArrayToHexStr(data))
	return
}
func GenFSModuleData0306(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x03, 0x06, 0xFF, 0xFF}
	ModelNum := 0                       // 模型总数
	ModelCode, _ := strconv.Atoi(code3) // 模型序号
	contentBytes := make([]byte, 0)     // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "电源状态" {
			ModelNum++
		}
	}
	data = append(data, byte(ModelNum), byte(ModelCode)) // 模型总数和序号
	data = append(data, 0x03)                            // 变量类型
	found := false
	var addrArr [3]byte
	for _, row := range fse.FSModule {
		if row.ModuleType == "电源状态" && row.Code3 == code3 {
			contentModel := PowerStateModel{}
			err = json.Unmarshal([]byte(row.JsonDetail), &contentModel)
			if err != nil {
				return
			}
			if !tools.IsValidIP(contentModel.IP) {
				err = errors.New("IP地址格式错误")
				return
			}
			data = append(data, contentModel.PLCType) // PLC类型
			ipArr := strings.Split(contentModel.IP, ".")
			ip1, _ := strconv.Atoi(ipArr[0])
			ip2, _ := strconv.Atoi(ipArr[1])
			ip3, _ := strconv.Atoi(ipArr[2])
			ip4, _ := strconv.Atoi(ipArr[3])
			portBytes := tools.Uint16ToBytes(contentModel.Port, fse.IntEndian)
			data = append(data, byte(ip1), byte(ip2), byte(ip3), byte(ip4), portBytes[0], portBytes[1]) // IP地址和端口

			data = append(data, contentModel.RunningStateType)
			b := tools.Uint16ToBytes(contentModel.RunningStateBlockValue, fse.IntEndian)
			data = append(data, b[:]...)

			addrArr = tools.PlcAddrToBytes(contentModel.RunningStateAddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)

			data = append(data, contentModel.ErrorStateType)
			b = tools.Uint16ToBytes(contentModel.ErrorStateBlockValue, fse.IntEndian)
			data = append(data, b[:]...)
			addrArr = tools.PlcAddrToBytes(contentModel.ErrorStateAddrValue, fse.IntEndian, contentModel.PLCType)
			data = append(data, addrArr[:]...)
			found = true
			break
		}
	}
	if !found {
		err = errors.New("未找到当前模型数据")
		return
	}
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	fmt.Printf("DEBUG GenFSModuleData0306: %s", tools.ByteArrayToHexStr(data))
	return
}
func GenFSModuleData0307(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x03, 0x07, 0x00, 0x24}
	ModelNum := 0                       // 模型总数
	ModelCode, _ := strconv.Atoi(code3) // 模型序号
	contentBytes := make([]byte, 0)     // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "模态采集" {
			ModelNum++
		}
	}
	data = append(data, byte(ModelNum), byte(ModelCode)) // 模型总数和序号
	data = append(data, 0x02)                            // 内部变量
	found := false
	for _, row := range fse.FSModule {
		if row.ModuleType == "模态采集" && row.Code3 == code3 {
			contentModel := ModeCollectModel{}
			err = json.Unmarshal([]byte(row.JsonDetail), &contentModel)
			if err != nil {
				return
			}
			data = append(data, Addr2Bytes(contentModel.StimulatePoint)...)
			data = append(data, Addr2Bytes(contentModel.ResponsePoint)...)
			data = append(data, Addr2Bytes(contentModel.StartControl)...)
			data = append(data, Addr2Bytes(contentModel.StopControl)...)
			data = append(data, Addr2Bytes(contentModel.StartState)...)
			data = append(data, Addr2Bytes(contentModel.StopState)...)

			found = true
			break
		}
	}
	if !found {
		err = errors.New("未找到当前模型数据")
		return
	}
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}
func GenFSModuleData0308(fse *FSEquip, code3 string) (data []byte, err error) {
	data = []byte{0x5A, 0x03, 0x08, 0x00, 0x24}
	ModelNum := 0                       // 模型总数
	ModelCode, _ := strconv.Atoi(code3) // 模型序号
	contentBytes := make([]byte, 0)     // 内容部分
	for _, row := range fse.FSModule {
		if row.ModuleType == "故障诊断" {
			ModelNum++
		}
	}
	data = append(data, byte(ModelNum), byte(ModelCode)) // 模型总数和序号
	data = append(data, 0x01)                            // 内部变量
	found := false
	for _, row := range fse.FSModule {
		if row.ModuleType == "故障诊断" && row.Code3 == code3 {
			contentModel := DiagModel{}
			err = json.Unmarshal([]byte(row.JsonDetail), &contentModel)
			if err != nil {
				return
			}
			data = append(data, tools.Float32ToBytes(float32(contentModel.DiagModeValue), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.DiagParam1Value), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.DiagParam2Value), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.DiagParam3Value), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.DiagParam4Value), fse.FloatEndian)...)
			data = append(data, tools.Float32ToBytes(float32(contentModel.DiagParam5Value), fse.FloatEndian)...)
			found = true
			break
		}
	}
	if !found {
		err = errors.New("未找到当前模型数据")
		return
	}
	// 内容部分
	data = append(data, contentBytes...)
	// 尾部
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}

func GenFSFrameData0401() (data []byte) {
	data = []byte{0x5A, 0x04, 0x01, 0x00, 0x0C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA5}
	return
}
func GenFSFrameData0501() (data []byte) {
	data = []byte{0x5A, 0x05, 0x01, 0x00, 0x0C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA5}
	return
}

//	func GenFSFrameData0402(list []*FrameItem) (data []byte) {
//		data = []byte{0x5A, 0x04, 0x02, 0xCC, 0xCC, 0x01, 0x01}
//		contentBytes := make([]byte, 0)
//		for _, item := range list {
//			upperLimitValue := tools.Float32ToBytes(float32(item.UpperLimitValue), fse.FloatEndian)
//			lowerLimitValue := tools.Float32ToBytes(float32(item.LowerLimitValue), fse.FloatEndian)
//			upper2LimitValue := tools.Float32ToBytes(float32(item.Upper2LimitValue), fse.FloatEndian)
//			lower2LimitValue := tools.Float32ToBytes(float32(item.Lower2LimitValue), fse.FloatEndian)
//			rangeUpperLimit := tools.Float32ToBytes(float32(item.RangeUpperLimit), fse.FloatEndian)
//			rangeLowerLimit := tools.Float32ToBytes(float32(item.RangeLowerLimit), fse.FloatEndian)
//			contentBytes = append(contentBytes, upperLimitValue...)
//			contentBytes = append(contentBytes, lowerLimitValue...)
//			contentBytes = append(contentBytes, upper2LimitValue...)
//			contentBytes = append(contentBytes, lower2LimitValue...)
//			contentBytes = append(contentBytes, rangeUpperLimit...)
//			contentBytes = append(contentBytes, rangeLowerLimit...)
//			contentBytes = append(contentBytes, item.Shield)
//			contentBytes = append(contentBytes, item.AlertBit)
//			contentBytes = append(contentBytes, item.Formula)
//			contentBytes = append(contentBytes, item.DiagMode)
//		}
//		data = append(data, contentBytes...)
//		data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5)
//		FixDataLength(fse,data)
//		return
//	}
func GenFSFrameData0601() (data []byte) {
	data = []byte{0x5A, 0x06, 0x01, 0x00, 0x0C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA5}
	return
}
func GenFSFrameData0602() (data []byte) {
	data = []byte{0x5A, 0x06, 0x02, 0x00, 0x0C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA5}
	return
}
func GenFSFrameData0603(fse *FSEquip) (data []byte) {
	data = []byte{0x5A, 0x06, 0x03, 0xFF, 0xFF, 0x01, 0x01}

	data = append(data, fse.DS.AI, fse.DS.DI, fse.DS.AQ, fse.DS.DQ, fse.DS.Other)
	eDataBytes := tools.Uint16ToBytes(fse.DS.EData, fse.IntEndian)
	data = append(data, eDataBytes[:]...)
	data = append(data, fse.DS.Bengzu, fse.DS.Zengya, fse.DS.Pressure, 0x00)
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5)
	FixDataLength(fse, data)
	return
}

type DataPart0604 struct {
	ModuleType string  `json:"type"`   // 模块类型 00：AI；01:AQ 02：DQ 03:Other 04：泵组 05：增压泵 06：压力电磁阀 ;
	TypeValue  byte    `json:"-"`      // 见0604说明;注意这里的值和命名规则那个code2 不一样!不一样!不一样!
	Addr       byte    `json:"addr"`   // 模块地址, 模型序号
	Number     byte    `json:"number"` // 模块通道号,模型值序号
	Value      float32 `json:"value"`  // 修改值 ??? ,目前都是float32
}

// GenFSFrameData0604 旧版本, 已废弃
func GenFSFrameData0604(fse *FSEquip, list []*DataPart0604) (data []byte, err error) {
	if len(list) > 255 {
		err = errors.New("参数block数量不能超过255")
		return
	}
	data = []byte{0x5A, 0x06, 0x04, 0xFF, 0xFF, 0x01, 0x01}
	data = append(data, fse.DS.AI, fse.DS.DI, fse.DS.AQ, fse.DS.DQ, fse.DS.Other)
	eDataBytes := tools.Uint16ToBytes(fse.DS.EData, fse.IntEndian)
	data = append(data, eDataBytes[:]...)
	data = append(data, fse.DS.Bengzu, fse.DS.Zengya, fse.DS.Pressure, byte(len(list)))
	for _, row := range list {
		data = append(data, row.TypeValue, row.Addr, row.Number)
		b := tools.Float32ToBytes(row.Value, fse.FloatEndian)
		data = append(data, b...)
	}
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	return
}

func Bytes2Addr(code1, modelType string, modelNum, channelNum byte) (addr string) {
	if code1 != "" {
		code1 = code1 + "-"
	}
	code2 := ""
	code3 := fmt.Sprintf("%02d", modelNum)
	code4 := fmt.Sprintf("%03d", channelNum)
	switch modelType {
	case "AI":
		code2 = "00"
	case "AQ":
		code2 = "01"
	case "DI":
		code2 = "02"
	case "DQ":
		code2 = "03"
	case "Other":
		code2 = "04"
	}
	return code1 + code2 + "-" + code3 + "-" + code4
}

func ParseModel0502(fse *FSEquip, buffer []byte, code1 string) (m *BengzuModel) {
	m = &BengzuModel{}
	i := 0
	m.BengzuStartControlValue = FSBoolToNormalBool(buffer[i])
	i++
	m.BengzuStopControlValue = FSBoolToNormalBool(buffer[i])
	i++
	m.BengzuStartStateValue = FSBoolToNormalBool(buffer[i])
	i++
	m.BengzuStopStateValue = FSBoolToNormalBool(buffer[i])
	i++
	m.LiansuoValue = FSBoolToNormalBool(buffer[i])
	i++
	m.ControlMethodValue = buffer[i]
	i++
	m.BengzuParam1Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.BengzuParam2Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.BengzuParam3Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.BengzuParam4Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.BengzuParam5Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	i++ // 跳过变量类型
	m.BengqianPressure = Bytes2Addr(code1, "AI", buffer[i], buffer[i+1])
	i += 2
	m.BengqianStartControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.BengqianStopControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.BengqianStartState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.BengqianStopState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.QianjibengStartControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.QianjibengStopControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.QianjibengStartState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.QianjibengStopState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.LuocibengStartControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.LuocibengStopControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.LuocibengStartState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.LuocibengStopState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.RemoteLocal = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	return
}

func ParseModel0503(buffer []byte, code1 string) (m *ZengyaModel) {
	m = &ZengyaModel{}
	i := 0
	m.LiansuoValue = FSBoolToNormalBool(buffer[i])
	i++
	m.ControlMethodValue = buffer[i]
	i++
	i++ // 跳过变量类型
	m.BengqianPressure = Bytes2Addr(code1, "AI", buffer[i], buffer[i+1])
	i += 2
	m.BengqianStartControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.BengqianStopControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.BengqianStartState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.BengqianStopState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.ZengyaStartControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.ZengyaStopControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.ZengyaStartState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.ZengyaStopState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.RemoteLocal = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	return
}

func ParseModel0504(buffer []byte, code1 string) (m *DiantiaoSVModel) {
	m = &DiantiaoSVModel{}
	i := 0
	m.CurrentKaidu = Bytes2Addr(code1, "AI", buffer[i], buffer[i+1])
	i += 2
	m.SetKaidu = Bytes2Addr(code1, "AQ", buffer[i], buffer[i+1])
	i += 2
	m.Control = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.SetStep = Bytes2Addr(code1, "AQ", buffer[i], buffer[i+1])
	i += 2
	m.SelfInspection = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.Up = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.Down = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.AllOn = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.AllOff = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2

	m.AllOnState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.AllOffState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.QianjiPressure = Bytes2Addr(code1, "AI", buffer[i], buffer[i+1])
	i += 2
	m.HoujiPressure = Bytes2Addr(code1, "AI", buffer[i], buffer[i+1])
	i += 2
	m.DestPressure = Bytes2Addr(code1, "AQ", buffer[i], buffer[i+1])
	i += 2
	m.P = Bytes2Addr(code1, "AQ", buffer[i], buffer[i+1])
	i += 2
	m.I = Bytes2Addr(code1, "AQ", buffer[i], buffer[i+1])
	i += 2
	m.D = Bytes2Addr(code1, "AQ", buffer[i], buffer[i+1])
	i += 2
	m.CustomStartControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.CustomStopControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.CustomStartState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.CustomStopState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.PID = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.RemoteLocal = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.ControlMethod = Bytes2Addr(code1, "AQ", buffer[i], buffer[i+1])
	i += 2
	return
}

func ParseModel0505(buffer []byte, code1 string) (m *PressureSVModel) {
	m = &PressureSVModel{}
	i := 0
	m.LiansuoValue = FSBoolToNormalBool(buffer[i])
	i++
	m.ControlMethodValue = buffer[i]
	i += 2
	m.Pressure = Bytes2Addr(code1, "AI", buffer[i], buffer[i+1])
	i += 2

	m.SVStartControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.SVStopControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.SVStartState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.SVStopState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	return
}

func ParseModel0506(fse *FSEquip, buffer []byte) (m *PowerModel, err error) {
	m = &PowerModel{}
	i := 0
	m.PLCType = buffer[i]
	i++
	ip1 := buffer[i]
	i++
	ip2 := buffer[i]
	i++
	ip3 := buffer[i]
	i++
	ip4 := buffer[i]
	i++
	m.IP = fmt.Sprintf("%d.%d.%d.%d", ip1, ip2, ip3, ip4)
	m.Port = tools.BytesToUint16(buffer[i:i+2], fse.IntEndian)
	i += 2

	m.U1Type, m.U1BlockValue, m.U1AddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6
	m.U2Type, m.U2BlockValue, m.U2AddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6
	m.U3Type, m.U3BlockValue, m.U3AddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6

	m.I1Type, m.I1BlockValue, m.I1AddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6
	m.I2Type, m.I2BlockValue, m.I2AddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6
	m.I3Type, m.I3BlockValue, m.I3AddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6

	m.FType, m.FBlockValue, m.FAddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6

	m.ApparentPowerType, m.ActivePowerBlockValue, m.ActivePowerAddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6
	m.ReactivePowerType, m.ReactivePowerBlockValue, m.ReactivePowerAddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6
	m.ApparentPowerType, m.ApparentPowerBlockValue, m.ApparentPowerAddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6
	return
}

func ParseModel0507(fse *FSEquip, buffer []byte) (m *PowerStateModel, err error) {
	m = &PowerStateModel{}
	i := 0
	m.PLCType = buffer[i]
	i++
	ip1 := buffer[i]
	i++
	ip2 := buffer[i]
	i++
	ip3 := buffer[i]
	i++
	ip4 := buffer[i]
	i++
	m.IP = fmt.Sprintf("%d.%d.%d.%d", ip1, ip2, ip3, ip4)
	m.Port = tools.BytesToUint16(buffer[i:i+2], fse.IntEndian)
	i += 2

	m.RunningStateType, m.RunningStateBlockValue, m.RunningStateAddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6

	m.ErrorStateType, m.ErrorStateBlockValue, m.ErrorStateAddrValue = tools.PLCAddrBytesParse(buffer[i:i+6], fse.IntEndian)
	i += 6

	return
}

func ParseModel0508(buffer []byte, code1 string) (m *ModeCollectModel) {
	m = &ModeCollectModel{}
	i := 0
	m.StimulatePoint = Bytes2Addr(code1, "AI", buffer[i], buffer[i+1])
	i += 2
	m.ResponsePoint = Bytes2Addr(code1, "AI", buffer[i], buffer[i+1])
	i += 2
	m.StartControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.StopControl = Bytes2Addr(code1, "DQ", buffer[i], buffer[i+1])
	i += 2
	m.StartState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	i += 2
	m.StopState = Bytes2Addr(code1, "DI", buffer[i], buffer[i+1])
	return
}

func ParseModel0509(fse *FSEquip, buffer []byte, code1 string) (m *DiagModel) {
	m = &DiagModel{}
	i := 0
	m.DiagModeValue = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.DiagParam1Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.DiagParam2Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.DiagParam3Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.DiagParam4Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	i += 4
	m.DiagParam5Value = float64(tools.BytesToFloat32(buffer[i:i+4], fse.FloatEndian))
	return
}

func Display0602(str string) {
	if global.DisplayFS0602 {
		fmt.Printf("%s", str)
	}
}

// GetAddrFromFSE 通过模块类型、模块号、通道号、字段名获取绑定的变量地址;
func GetAddrFromFSE(fse *FSEquip, moduleType string, moduleNumber int, channelNumber int, fieldName string) (addr string) {
	code3 := fmt.Sprintf("%02d", moduleNumber)
	for _, module := range fse.FSModule {
		if module.ModuleType == moduleType && module.Code3 == code3 {
			switch module.ModuleType {
			case "AI":
				return fmt.Sprintf("%s-%s-%02d-%03d", fse.Code1, "00", moduleNumber, channelNumber)
			case "AQ":
				return fmt.Sprintf("%s-%s-%02d-%03d", fse.Code1, "01", moduleNumber, channelNumber)
			case "DI":
				return fmt.Sprintf("%s-%s-%02d-%03d", fse.Code1, "02", moduleNumber, channelNumber)
			case "DQ":
				return fmt.Sprintf("%s-%s-%02d-%03d", fse.Code1, "03", moduleNumber, channelNumber)
			case "Other":
				return fmt.Sprintf("%s-%s-%02d-%03d", fse.Code1, "04", moduleNumber, channelNumber)
			case "泵组电磁阀":
				m := BengzuModel{}
				err := json.Unmarshal([]byte(module.JsonDetail), &m)
				if err != nil {
					j_log.LogError([]interface{}{"json error GetAddrFromFSE(泵组电磁阀)", err.Error()})
				}
				switch fieldName {
				case "开控制":
					return m.BengzuStartControl
				case "关控制":
					return m.BengzuStopControl
				case "开状态":
					return m.BengqianStartState
				case "关状态":
					return m.BengqianStopState
				case "连锁":
					return m.Liansuo
				default:
					j_log.LogError([]interface{}{fmt.Sprintf("设备FS%s 泵组电磁阀%02d中的字段%s暂不支持", fse.Code1, moduleNumber, fieldName)})
				}
				return m.BengzuStartControl
			case "增压泵电磁阀":
				m := ZengyaModel{}
				err := json.Unmarshal([]byte(module.JsonDetail), &m)
				if err != nil {
					j_log.LogError([]interface{}{"json error GetAddrFromFSE(增压泵电磁阀)", err.Error()})
				}
				switch fieldName {
				case "连锁":
					return m.Liansuo
				default:
					j_log.LogError([]interface{}{fmt.Sprintf("设备FS%s 增压泵电磁阀%02d中的字段%s暂不支持", fse.Code1, moduleNumber, fieldName)})
				}
			case "压力电磁阀":
				m := PressureSVModel{}
				err := json.Unmarshal([]byte(module.JsonDetail), &m)
				if err != nil {
					j_log.LogError([]interface{}{"json error GetAddrFromFSE(压力电磁阀)", err.Error()})
				}
				switch fieldName {
				case "连锁":
					return m.Liansuo
				default:
					j_log.LogError([]interface{}{fmt.Sprintf("设备FS%s 压力电磁阀%02d中的字段%s暂不支持", fse.Code1, moduleNumber, fieldName)})
				}
			}
			break
		}
	}
	//fmt.Printf("未找到当前模块序号 %s-%02d\n", moduleType, moduleNumber)
	return
}

// UpdateAQDQValueSingle 运行同步修改AQ DQ值 以及AI中的屏蔽 控制模型中的值
func UpdateAQDQValueSingle(variable *Variable, addr string, value float64) (data []byte, err error) {
	data = make([]byte, 0)
	fse, ok := RunningFSMap.Get(variable.FSID)
	if !ok {
		err = errors.New("FS设备TCP未连接")
		return
	}
	if fse.RunningState != 2 {
		err = errors.New("FS设备TCP未连接" + fse.Detail)
		return
	}
	//if fse.Stage == 0 {
	//	err = errors.New("FS设备处于组态阶段, 不可操作")
	//	return
	//}

	data = []byte{0x5A, 0x06, 0x04, 0xFF, 0xFF, 0x01, 0x01}
	data = append(data, fse.DS.AI, fse.DS.DI, fse.DS.AQ, fse.DS.DQ, fse.DS.Other)
	eDataBytes := tools.Uint16ToBytes(fse.DS.EData, fse.IntEndian)
	data = append(data, eDataBytes[:]...)
	data = append(data, fse.DS.Bengzu, fse.DS.Zengya, fse.DS.Pressure, byte(1))

	moduleNumber, _ := strconv.Atoi(variable.Code3)
	channelNumber, _ := strconv.Atoi(variable.Code4)
	partValue := make([]byte, 0)
	switch variable.Code2 {
	case "00": // AI只能修改屏壁值
		err = errors.New(fmt.Sprintf("变量%s为AI类型,只能修改屏蔽值", addr))
		return
		//partValue = append(partValue, 0x00, byte(moduleNumber), byte(channelNumber))
		//partValue = append(partValue, byte(value))
	case "01": // AQ
		valueByte := tools.Float32ToBytes4(float32(value), fse.FloatEndian)
		partValue = append(partValue, 0x01, byte(moduleNumber), byte(channelNumber))
		partValue = append(partValue, valueByte[:]...)
	case "03": // DQ
		partValue = append(partValue, 0x02, byte(moduleNumber), byte(channelNumber))
		partValue = append(partValue, byte(value))
	case "04": // Other
		switch variable.ChannelType {
		case "AI": // AI只能修改屏壁值
			err = errors.New(fmt.Sprintf("变量%s为Other下AI类型,只能修改屏蔽值", addr))
			return
			//partValue = append(partValue, 0x03, byte(moduleNumber), byte(channelNumber))
			//partValue = append(partValue, byte(value))
		case "AQ":
			valueByte := tools.Float32ToBytes4(float32(value), fse.FloatEndian)
			partValue = append(partValue, 0x03, byte(moduleNumber), byte(channelNumber))
			partValue = append(partValue, valueByte[:]...)
		case "DQ":
			partValue = append(partValue, 0x03, byte(moduleNumber), byte(channelNumber))
			partValue = append(partValue, byte(value))
		default:
			err = errors.New(fmt.Sprintf("当前变量不支持修改, addr=%s, channel_type=%s", variable.Addr, variable.ChannelType))
			return
		}
	case "05": // 泵组电磁阀
		fsm := &FSModel{}
		exist, err2 := fsm.Exists(variable.ModuleID)
		if !exist {
			err = errors.New(fmt.Sprintf("未找到当前变量所属模型信息, addr=%s", variable.Addr))
			return
		}
		m := &BengzuModel{}
		err2 = json.Unmarshal([]byte(fsm.JsonDetail), m)
		if err2 != nil {
			err = errors.New(fmt.Sprintf("json解析失败, addr=%s,JsonDetail=%s:%s", variable.Addr, fsm.JsonDetail, err2.Error()))
			return
		}
		number := 0
		if m.BengzuStartControl == addr {
			number = 1
		} else if m.BengzuStopControl == addr {
			number = 2
		} else if m.Liansuo == addr {
			number = 3
		} else {
			err = errors.New("当前变量所属模型未使用此变量地址")
			return
		}
		partValue = append(partValue, 0x04, byte(moduleNumber), byte(number))
		partValue = append(partValue, byte(value))
	case "06": // 增压泵电磁阀
		fsm := &FSModel{}
		exist, err2 := fsm.Exists(variable.ModuleID)
		if !exist {
			err = errors.New(fmt.Sprintf("未找到当前变量所属模型信息, addr=%s", variable.Addr))
			return
		}
		m := &ZengyaModel{}
		err2 = json.Unmarshal([]byte(fsm.JsonDetail), m)
		if err2 != nil {
			err = errors.New(fmt.Sprintf("json解析失败, addr=%s,JsonDetail=%s:%s", variable.Addr, fsm.JsonDetail, err2.Error()))
			return
		}
		number := 0
		if m.Liansuo == addr {
			number = 1
		} else {
			err = errors.New("当前变量所属模型未使用此变量地址")
			return
		}
		partValue = append(partValue, 0x05, byte(moduleNumber), byte(number))
		partValue = append(partValue, byte(value))
	case "08": // 压力电磁阀
		fsm := &FSModel{}
		exist, err2 := fsm.Exists(variable.ModuleID)
		if !exist {
			err = errors.New(fmt.Sprintf("未找到当前变量所属模型信息, addr=%s", variable.Addr))
			return
		}
		m := &PressureSVModel{}
		err2 = json.Unmarshal([]byte(fsm.JsonDetail), m)
		if err2 != nil {
			err = errors.New(fmt.Sprintf("json解析失败, addr=%s,JsonDetail=%s:%s", variable.Addr, fsm.JsonDetail, err2.Error()))
			return
		}
		number := 0
		if m.Liansuo == addr {
			number = 1
		} else {
			err = errors.New("当前变量所属模型未使用此变量地址")
			return
		}
		partValue = append(partValue, 0x06, byte(moduleNumber), byte(number))
		partValue = append(partValue, byte(value))
	default:
		err = errors.New(fmt.Sprintf("当前自研设备变量不支持修改, addr=%s", variable.Addr))
		return
	}

	data = append(data, partValue...)
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)

	_, err = fse.Write(data)
	if err != nil {
		err = errors.New("TCP发送失败" + err.Error())
		return
	}
	return
}
func UpdateAQDQShieldSingle(variable *Variable, value float64) (data []byte, err error) {
	data = make([]byte, 0)
	fse, ok := RunningFSMap.Get(variable.FSID)
	if !ok {
		err = errors.New("FS设备TCP未连接")
		return
	}
	if fse.RunningState != 2 {
		err = errors.New("FS设备TCP未连接" + fse.Detail)
		return
	}
	if fse.Stage == 0 {
		err = errors.New("FS设备处于组态阶段, 不可操作")
		return
	}

	data = []byte{0x5A, 0x06, 0x04, 0xFF, 0xFF, 0x01, 0x01}
	data = append(data, fse.DS.AI, fse.DS.DI, fse.DS.AQ, fse.DS.DQ, fse.DS.Other)
	eDataBytes := tools.Uint16ToBytes(fse.DS.EData, fse.IntEndian)
	data = append(data, eDataBytes[:]...)
	data = append(data, fse.DS.Bengzu, fse.DS.Zengya, fse.DS.Pressure, byte(1))

	moduleNumber, _ := strconv.Atoi(variable.Code3)
	channelNumber, _ := strconv.Atoi(variable.Code4)
	partValue := make([]byte, 0)
	switch variable.Code2 {
	case "00": // AI只能修改屏壁值
		partValue = append(partValue, 0x00, byte(moduleNumber), byte(channelNumber))
		partValue = append(partValue, byte(value))
	case "04": // Other
		switch variable.ChannelType {
		case "AI": // AI只能修改屏壁值
			partValue = append(partValue, 0x03, byte(moduleNumber), byte(channelNumber))
			partValue = append(partValue, byte(value))
		default:
			err = errors.New(fmt.Sprintf("当前变量不支持修改屏蔽值, addr=%s, channel_type=%s", variable.Addr, variable.ChannelType))
			return
		}
	default:
		err = errors.New(fmt.Sprintf("当前变量不支持修改屏蔽值, addr=%s, channel_type=%s", variable.Addr, variable.ChannelType))
		return
	}

	data = append(data, partValue...)
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5) // 状态,保留,帧尾
	FixDataLength(fse, data)
	_, err = fse.Write(data)
	if err != nil {
		err = errors.New("TCP发送失败" + err.Error())
		return
	}
	return
}
func UpdateMemShieldAlert(addr string, shieldV uint8, alertV uint8) {
	tmpVar, ok := VariablesMap.Get(addr + ".shield")
	if shieldV == 12 {
		shieldV = 1
	} else {
		shieldV = 0
	}
	if ok {
		tmpVar.Value = float64(shieldV)
	} else {
		j_log.LogWarning([]interface{}{fmt.Sprintf("未找到变量 %s", addr+".shield")})
	}
	tmpVar, ok = VariablesMap.Get(addr + ".alert")
	if ok {
		tmpVar.Value = float64(alertV)
	} else {
		j_log.LogWarning([]interface{}{fmt.Sprintf("未找到变量 %s", addr+".alert")})
	}
	return
}

type Data0605 struct {
	LimitType     uint8   // 修改类型 00:上限,01:下限,02:上上限,03:下下限
	ModuleType    uint8   // 模块类型 AI:00,Other:01
	ModuleNumber  uint8   // 模块地址(模块号)
	ChannelNumber uint8   // 通道号
	Value         float64 // 修改值
}

// UpdateAILimitValue 修改AI限值
func UpdateAILimitValue(addr string, list []*Data0605) (err error) {
	if len(list) == 0 {
		return
	}
	variable, ok := VariablesMap.Get(addr)
	if !ok {
		err = errors.New("未找到变量")
		j_log.LogWarning([]interface{}{fmt.Sprintf("未找到变量 %s", addr)})
		return
	}
	if variable.FSID == 0 || variable.ChannelType != "AI" {
		err = errors.New("变量不是AI类型")
		j_log.LogWarning([]interface{}{fmt.Sprintf("变量 %s的通道类型 %s 不是AI类型", variable.FieldName, variable.ChannelType)})
		return
	}
	fse, ok := RunningFSMap.Get(variable.FSID)
	if !ok {
		err = errors.New("变量所属设备未运行")
		return
	}
	moduleType := byte(0)
	if variable.Code2 == "00" {
		moduleType = byte(0)
	} else {
		moduleType = 1
	}
	code3N, _ := strconv.Atoi(variable.Code3)
	code4N, _ := strconv.Atoi(variable.Code4)
	moduleNumber := byte(code3N)
	channelNumber := byte(code4N)
	data := []byte{0x5A, 0x06, 0x05, 0xFF, 0xFF, 0x01, 0x01}
	data = append(data, fse.DS.AI, fse.DS.DI, fse.DS.AQ, fse.DS.DQ, fse.DS.Other)
	eDataBytes := tools.Uint16ToBytes(fse.DS.EData, fse.IntEndian)
	data = append(data, eDataBytes[:]...)
	data = append(data, fse.DS.Bengzu, fse.DS.Zengya, fse.DS.Pressure, uint8(len(list)))
	for _, row := range list {
		data = append(data, row.LimitType, moduleType, moduleNumber, channelNumber)
		vb := tools.Float32ToBytes(float32(row.Value), fse.FloatEndian)
		data = append(data, vb...)
	}
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5)
	FixDataLength(fse, data)
	_, err = fse.TcpClient.Connection.Write(data)
	if err != nil {
		j_log.LogWarning([]interface{}{fmt.Sprintf("自研设备%s tcp写入失败", fse.Name)})
	}
	return
}

func FSToLocalByte(b byte) byte {
	if b == 12 {
		b = 1
	} else {
		b = 0
	}
	return b
}

func LocalToFSByte(b byte) byte {
	if b == 1 {
		b = 12
	} else {
		b = 11
	}
	return b
}

func FSBoolToNormalBool(b byte) byte {
	if b == 0x0C {
		return 1
	}
	return 0
}
func NormalBoolToFSBool(b byte) byte {
	if b == 1 {
		return 0x0C
	}
	return 0x0B
}
